Hi Bram, 2015-6-25(Thu) 23:09:44 UTC+9 Bram Moolenaar: > Patch 7.4.755 > Problem: It is not easy to count the number of characters. > Solution: Add the skipcc argument to strchars(). (Hirohito Higashi, Ken > Takata) > Files: runtime/doc/eval.txt, src/eval.c, src/testdir/test_utf8.in, > src/testdir/test_utf8.ok > > > *** ../vim-7.4.754/runtime/doc/eval.txt 2015-03-20 17:36:38.618949214 > +0100 > --- runtime/doc/eval.txt 2015-06-25 15:59:53.104434430 +0200 > *************** > *** 1984,1990 **** > sqrt( {expr}) Float square root of {expr} > str2float( {expr}) Float convert String to Float > str2nr( {expr} [, {base}]) Number convert String to Number > ! strchars( {expr}) Number character length of the String {expr} > strdisplaywidth( {expr} [, {col}]) Number display length of the String > {expr} > strftime( {format}[, {time}]) String time in specified format > stridx( {haystack}, {needle}[, {start}]) > --- 1985,1991 ---- > sqrt( {expr}) Float square root of {expr} > str2float( {expr}) Float convert String to Float > str2nr( {expr} [, {base}]) Number convert String to Number > ! strchars( {expr} [, {skipcc}]) Number character length of the String > {expr} > strdisplaywidth( {expr} [, {col}]) Number display length of the String > {expr} > strftime( {format}[, {time}]) String time in specified format > stridx( {haystack}, {needle}[, {start}]) > *************** > *** 5792,5806 **** > Text after the number is silently ignored. > > > ! strchars({expr}) *strchars()* > The result is a Number, which is the number of characters > ! String {expr} occupies. Composing characters are counted > ! separately. > Also see |strlen()|, |strdisplaywidth()| and |strwidth()|. > > strdisplaywidth({expr}[, {col}]) *strdisplaywidth()* > The result is a Number, which is the number of display cells > ! String {expr} occupies on the screen. > When {col} is omitted zero is used. Otherwise it is the > screen column where to start. This matters for Tab > characters. > --- 5839,5855 ---- > Text after the number is silently ignored. > > > ! strchars({expr} [, {skipcc}]) > *strchars()* > The result is a Number, which is the number of characters > ! in String {expr}. > ! When {skipcc} is omitted or zero, composing characters are > ! counted separately. > ! When {skipcc} set to 1, Composing characters are ignored. > Also see |strlen()|, |strdisplaywidth()| and |strwidth()|. > > strdisplaywidth({expr}[, {col}]) *strdisplaywidth()* > The result is a Number, which is the number of display cells > ! String {expr} occupies on the screen when it starts a {col}. > When {col} is omitted zero is used. Otherwise it is the > screen column where to start. This matters for Tab > characters. > *************** > *** 5866,5880 **** > *strlen()* > strlen({expr}) The result is a Number, which is the length of the > String > {expr} in bytes. > - If you want to count the number of multi-byte characters (not > - counting composing characters) use something like this: > > - > - :let len = strlen(substitute(str, ".", "x", "g")) > - < > If the argument is a Number it is first converted to a String. > For other types an error is given. > ! Also see |len()|, |strchars()|, |strdisplaywidth()| and > ! |strwidth()|. > > strpart({src}, {start}[, {len}]) *strpart()* > The result is a String, which is part of {src}, starting from > --- 5915,5925 ---- > *strlen()* > strlen({expr}) The result is a Number, which is the length of the > String > {expr} in bytes. > If the argument is a Number it is first converted to a String. > For other types an error is given. > ! If you want to count the number of multi-byte characters use > ! |strchars()|. > ! Also see |len()|, |strdisplaywidth()| and |strwidth()|. > > strpart({src}, {start}[, {len}]) *strpart()* > The result is a String, which is part of {src}, starting from > *** ../vim-7.4.754/src/eval.c 2015-06-19 21:06:04.664521324 +0200 > --- src/eval.c 2015-06-25 15:53:55.992189567 +0200 > *************** > *** 3810,3816 **** > /* (un)lock a List item. */ > item_lock(&lp->ll_li->li_tv, deep, lock); > else > ! /* un(lock) a Dictionary item. */ > item_lock(&lp->ll_di->di_tv, deep, lock); > > return ret; > --- 3810,3816 ---- > /* (un)lock a List item. */ > item_lock(&lp->ll_li->li_tv, deep, lock); > else > ! /* (un)lock a Dictionary item. */ > item_lock(&lp->ll_di->di_tv, deep, lock); > > return ret; > *************** > *** 8309,8315 **** > {"str2float", 1, 1, f_str2float}, > #endif > {"str2nr", 1, 2, f_str2nr}, > ! {"strchars", 1, 1, f_strchars}, > {"strdisplaywidth", 1, 2, f_strdisplaywidth}, > #ifdef HAVE_STRFTIME > {"strftime", 1, 2, f_strftime}, > --- 8309,8315 ---- > {"str2float", 1, 1, f_str2float}, > #endif > {"str2nr", 1, 2, f_str2nr}, > ! {"strchars", 1, 2, f_strchars}, > {"strdisplaywidth", 1, 2, f_strdisplaywidth}, > #ifdef HAVE_STRFTIME > {"strftime", 1, 2, f_strftime}, > *************** > *** 18372,18389 **** > typval_T *rettv; > { > char_u *s = get_tv_string(&argvars[0]); > #ifdef FEAT_MBYTE > varnumber_T len = 0; > > ! while (*s != NUL) > { > ! mb_cptr2char_adv(&s); > ! ++len; > ! } > ! rettv->vval.v_number = len; > #else > ! rettv->vval.v_number = (varnumber_T)(STRLEN(s)); > #endif > } > > /* > --- 18372,18401 ---- > typval_T *rettv; > { > char_u *s = get_tv_string(&argvars[0]); > + int skipcc = 0; > #ifdef FEAT_MBYTE > varnumber_T len = 0; > + int (*func_mb_ptr2char_adv)(char_u **pp); > + #endif > > ! if (argvars[1].v_type != VAR_UNKNOWN) > ! skipcc = get_tv_number_chk(&argvars[1], NULL); > ! if (skipcc < 0 || skipcc > 1) > ! EMSG(_(e_invarg)); > ! else > { > ! #ifdef FEAT_MBYTE > ! func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; > ! while (*s != NUL) > ! { > ! func_mb_ptr2char_adv(&s); > ! ++len; > ! } > ! rettv->vval.v_number = len; > #else > ! rettv->vval.v_number = (varnumber_T)(STRLEN(s)); > #endif > + } > } > > /* > *** ../vim-7.4.754/src/testdir/test_utf8.in 2014-08-16 18:36:38.593993280 > +0200 > --- src/testdir/test_utf8.in 2015-06-25 15:53:55.992189567 +0200 > *************** > *** 11,16 **** > --- 11,22 ---- > : > :bwipeout! > :$put=r > + :" Test for built-in function strchars() > + :for str in ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"] > + : $put=strchars(str) > + : $put=strchars(str, 0) > + : $put=strchars(str, 1) > + :endfor > :call garbagecollect(1) > :/^start:/,$wq! test.out > ENDTEST > *** ../vim-7.4.754/src/testdir/test_utf8.ok 2014-08-16 18:36:38.593993280 > +0200 > --- src/testdir/test_utf8.ok 2015-06-25 15:53:55.992189567 +0200 > *************** > *** 2,4 **** > --- 2,19 ---- > axaa > xあああ > bxbb > + 1 > + 1 > + 1 > + 3 > + 3 > + 3 > + 2 > + 2 > + 1 > + 3 > + 3 > + 1 > + 1 > + 1 > + 1 > *** ../vim-7.4.754/src/version.c 2015-06-25 13:57:20.033431073 +0200 > --- src/version.c 2015-06-25 15:55:26.071242187 +0200 > *************** > *** 743,744 **** > --- 743,746 ---- > { /* Add new patch number below this line */ > + /**/ > + 755, > /**/
Thanks for include my patch! But part of runtime/doc/eval.txt was missing. The following difference does not reflect. > *** 5792,5806 **** > Text after the number is silently ignored. > > > ! strchars({expr}) *strchars()* > The result is a Number, which is the number of characters > ! String {expr} occupies. Composing characters are counted > ! separately. > Also see |strlen()|, |strdisplaywidth()| and |strwidth()|. > > strdisplaywidth({expr}[, {col}]) *strdisplaywidth()* > The result is a Number, which is the number of display cells > ! String {expr} occupies on the screen. > When {col} is omitted zero is used. Otherwise it is the > screen column where to start. This matters for Tab > characters. > --- 5839,5855 ---- > Text after the number is silently ignored. > > > ! strchars({expr} [, {skipcc}]) > *strchars()* > The result is a Number, which is the number of characters > ! in String {expr}. > ! When {skipcc} is omitted or zero, composing characters are > ! counted separately. > ! When {skipcc} set to 1, Composing characters are ignored. > Also see |strlen()|, |strdisplaywidth()| and |strwidth()|. > > strdisplaywidth({expr}[, {col}]) *strdisplaywidth()* > The result is a Number, which is the number of display cells > ! String {expr} occupies on the screen when it starts a {col}. > When {col} is omitted zero is used. Otherwise it is the > screen column where to start. This matters for Tab > characters. > *************** I confirmed by hg. $ hg diff -c v7-4-755 diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -1985,7 +1985,7 @@ sqrt( {expr}) Float square root of {expr} str2float( {expr}) Float convert String to Float str2nr( {expr} [, {base}]) Number convert String to Number -strchars( {expr}) Number character length of the String {expr} +strchars( {expr} [, {skipcc}]) Number character length of the String {expr} strdisplaywidth( {expr} [, {col}]) Number display length of the String {expr} strftime( {format}[, {time}]) String time in specified format stridx( {haystack}, {needle}[, {start}]) @@ -5913,15 +5913,11 @@ *strlen()* strlen({expr}) The result is a Number, which is the length of the String {expr} in bytes. - If you want to count the number of multi-byte characters (not - counting composing characters) use something like this: > - - :let len = strlen(substitute(str, ".", "x", "g")) -< If the argument is a Number it is first converted to a String. For other types an error is given. - Also see |len()|, |strchars()|, |strdisplaywidth()| and - |strwidth()|. + If you want to count the number of multi-byte characters use + |strchars()|. + Also see |len()|, |strdisplaywidth()| and |strwidth()|. strpart({src}, {start}[, {len}]) *strpart()* The result is a String, which is part of {src}, starting from diff --git a/src/eval.c b/src/eval.c --- a/src/eval.c +++ b/src/eval.c @@ -3810,7 +3810,7 @@ /* (un)lock a List item. */ item_lock(&lp->ll_li->li_tv, deep, lock); else - /* un(lock) a Dictionary item. */ + /* (un)lock a Dictionary item. */ item_lock(&lp->ll_di->di_tv, deep, lock); return ret; @@ -8309,7 +8309,7 @@ {"str2float", 1, 1, f_str2float}, #endif {"str2nr", 1, 2, f_str2nr}, - {"strchars", 1, 1, f_strchars}, + {"strchars", 1, 2, f_strchars}, {"strdisplaywidth", 1, 2, f_strdisplaywidth}, #ifdef HAVE_STRFTIME {"strftime", 1, 2, f_strftime}, @@ -18372,18 +18372,30 @@ typval_T *rettv; { char_u *s = get_tv_string(&argvars[0]); + int skipcc = 0; #ifdef FEAT_MBYTE varnumber_T len = 0; - - while (*s != NUL) - { - mb_cptr2char_adv(&s); - ++len; - } - rettv->vval.v_number = len; + int (*func_mb_ptr2char_adv)(char_u **pp); +#endif + + if (argvars[1].v_type != VAR_UNKNOWN) + skipcc = get_tv_number_chk(&argvars[1], NULL); + if (skipcc < 0 || skipcc > 1) + EMSG(_(e_invarg)); + else + { +#ifdef FEAT_MBYTE + func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv; + while (*s != NUL) + { + func_mb_ptr2char_adv(&s); + ++len; + } + rettv->vval.v_number = len; #else - rettv->vval.v_number = (varnumber_T)(STRLEN(s)); -#endif + rettv->vval.v_number = (varnumber_T)(STRLEN(s)); +#endif + } } /* diff --git a/src/testdir/test_utf8.in b/src/testdir/test_utf8.in --- a/src/testdir/test_utf8.in +++ b/src/testdir/test_utf8.in @@ -11,6 +11,12 @@ : :bwipeout! :$put=r +:" Test for built-in function strchars() +:for str in ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"] +: $put=strchars(str) +: $put=strchars(str, 0) +: $put=strchars(str, 1) +:endfor :call garbagecollect(1) :/^start:/,$wq! test.out ENDTEST diff --git a/src/testdir/test_utf8.ok b/src/testdir/test_utf8.ok --- a/src/testdir/test_utf8.ok +++ b/src/testdir/test_utf8.ok @@ -2,3 +2,18 @@ axaa xあああ bxbb +1 +1 +1 +3 +3 +3 +2 +2 +1 +3 +3 +1 +1 +1 +1 diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -742,6 +742,8 @@ static int included_patches[] = { /* Add new patch number below this line */ /**/ + 755, +/**/ 754, /**/ 753, Could you confirm this? -- Best regards, Hirohito Higashi (a.k.a h_east) -- -- You received this message from the "vim_dev" maillist. Do not top-post! Type your reply below the text you are replying to. For more information, visit http://www.vim.org/maillist.php --- You received this message because you are subscribed to the Google Groups "vim_dev" group. To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.