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.

Raspunde prin e-mail lui