To: vim_dev@googlegroups.com Subject: Patch 8.2.2606 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.2606 Problem: strchars() defaults to counting composing characters. Solution: Add strcharlen() which ignores composing characters. Files: runtime/doc/eval.txt, runtime/doc/usr_41.txt, src/evalfunc.c, src/testdir/test_utf8.vim *** ../vim-8.2.2605/runtime/doc/eval.txt 2021-02-06 12:38:47.623324174 +0100 --- runtime/doc/eval.txt 2021-03-14 18:46:48.334939793 +0100 *************** *** 2923,2932 **** ASCII/UTF8 value str2nr({expr} [, {base} [, {quoted}]]) Number convert String to Number strcharpart({str}, {start} [, {len}]) String {len} characters of {str} at character {start} ! strchars({expr} [, {skipcc}]) Number character length of the String {expr} strdisplaywidth({expr} [, {col}]) Number display length of the String {expr} strftime({format} [, {time}]) String format time with a specified format strgetchar({str}, {index}) Number get char {index} from {str} --- 2923,2933 ---- ASCII/UTF8 value str2nr({expr} [, {base} [, {quoted}]]) Number convert String to Number + strcharlen({expr}) Number character length of the String {expr} strcharpart({str}, {start} [, {len}]) String {len} characters of {str} at character {start} ! strchars({expr} [, {skipcc}]) Number character count of the String {expr} strdisplaywidth({expr} [, {col}]) Number display length of the String {expr} strftime({format} [, {time}]) String format time with a specified format strgetchar({str}, {index}) Number get char {index} from {str} *************** *** 10267,10275 **** Can also be used as a |method|: > GetText()->str2nr() strcharpart({src}, {start} [, {len}]) *strcharpart()* Like |strpart()| but using character index and length instead ! of byte index and length. When a character index is used where a character does not exist it is assumed to be one character. For example: > strcharpart('abc', -1, 2) --- 10277,10299 ---- Can also be used as a |method|: > GetText()->str2nr() + + strcharlen({expr}) *strcharlen()* + The result is a Number, which is the number of characters + in String {expr}. Composing characters are ignored. + |strchars()| can count the number of characters, counting + composing characters separately. + + Also see |strlen()|, |strdisplaywidth()| and |strwidth()|. + + Can also be used as a |method|: > + GetText()->strcharlen() + + strcharpart({src}, {start} [, {len}]) *strcharpart()* Like |strpart()| but using character index and length instead ! of byte index and length. Composing characters are counted ! separately. When a character index is used where a character does not exist it is assumed to be one character. For example: > strcharpart('abc', -1, 2) *************** *** 10278,10289 **** --- 10302,10316 ---- Can also be used as a |method|: > GetText()->strcharpart(5) + 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. + |strcharlen()| does the same. + Also see |strlen()|, |strdisplaywidth()| and |strwidth()|. {skipcc} is only available after 7.4.755. For backward *** ../vim-8.2.2605/runtime/doc/usr_41.txt 2021-02-06 12:38:47.623324174 +0100 --- runtime/doc/usr_41.txt 2021-03-14 18:48:39.142593444 +0100 *************** *** 611,617 **** stridx() first index of a short string in a long string strridx() last index of a short string in a long string strlen() length of a string in bytes ! strchars() length of a string in characters strwidth() size of string when displayed strdisplaywidth() size of string when displayed, deals with tabs setcellwidths() set character cell width overrides --- 611,618 ---- stridx() first index of a short string in a long string strridx() last index of a short string in a long string strlen() length of a string in bytes ! strcharlen() length of a string in characters ! strchars() number of characters in a string strwidth() size of string when displayed strdisplaywidth() size of string when displayed, deals with tabs setcellwidths() set character cell width overrides *** ../vim-8.2.2605/src/evalfunc.c 2021-03-10 16:08:22.737770798 +0100 --- src/evalfunc.c 2021-03-14 18:52:58.385829594 +0100 *************** *** 223,228 **** --- 223,229 ---- #endif static void f_str2list(typval_T *argvars, typval_T *rettv); static void f_str2nr(typval_T *argvars, typval_T *rettv); + static void f_strcharlen(typval_T *argvars, typval_T *rettv); static void f_strchars(typval_T *argvars, typval_T *rettv); static void f_strgetchar(typval_T *argvars, typval_T *rettv); static void f_stridx(typval_T *argvars, typval_T *rettv); *************** *** 1572,1577 **** --- 1573,1580 ---- ret_list_number, f_str2list}, {"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool, ret_number, f_str2nr}, + {"strcharlen", 1, 1, FEARG_1, NULL, + ret_number, f_strcharlen}, {"strcharpart", 2, 3, FEARG_1, NULL, ret_string, f_strcharpart}, {"strchars", 1, 2, FEARG_1, NULL, *************** *** 9236,9266 **** tv_get_string(&argvars[0]))); } /* * "strchars()" function */ static void f_strchars(typval_T *argvars, typval_T *rettv) { - char_u *s = tv_get_string(&argvars[0]); varnumber_T skipcc = FALSE; - varnumber_T len = 0; - int (*func_mb_ptr2char_adv)(char_u **pp); if (argvars[1].v_type != VAR_UNKNOWN) skipcc = tv_get_bool(&argvars[1]); if (skipcc < 0 || skipcc > 1) semsg(_(e_using_number_as_bool_nr), skipcc); else ! { ! 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; ! } } /* --- 9239,9283 ---- tv_get_string(&argvars[0]))); } + static void + strchar_common(typval_T *argvars, typval_T *rettv, int skipcc) + { + char_u *s = tv_get_string(&argvars[0]); + varnumber_T len = 0; + int (*func_mb_ptr2char_adv)(char_u **pp); + + 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; + } + + /* + * "strcharlen()" function + */ + static void + f_strcharlen(typval_T *argvars, typval_T *rettv) + { + strchar_common(argvars, rettv, TRUE); + } + /* * "strchars()" function */ static void f_strchars(typval_T *argvars, typval_T *rettv) { varnumber_T skipcc = FALSE; if (argvars[1].v_type != VAR_UNKNOWN) skipcc = tv_get_bool(&argvars[1]); if (skipcc < 0 || skipcc > 1) semsg(_(e_using_number_as_bool_nr), skipcc); else ! strchar_common(argvars, rettv, skipcc); } /* *** ../vim-8.2.2605/src/testdir/test_utf8.vim 2020-12-02 12:37:34.130954024 +0100 --- src/testdir/test_utf8.vim 2021-03-14 18:59:30.396751623 +0100 *************** *** 11,17 **** bwipeout! endfunc ! " Test for built-in function strchars() func Test_strchars() let inp = ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"] let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]] --- 11,17 ---- bwipeout! endfunc ! " Test for built-in functions strchars() and strcharlen() func Test_strchars() let inp = ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"] let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]] *************** *** 20,25 **** --- 20,32 ---- call assert_equal(exp[i][1], inp[i]->strchars(0)) call assert_equal(exp[i][2], strchars(inp[i], 1)) endfor + + let exp = [1, 3, 1, 1, 1] + for i in range(len(inp)) + call assert_equal(exp[i], inp[i]->strcharlen()) + call assert_equal(exp[i], strcharlen(inp[i])) + endfor + call assert_fails("let v=strchars('abc', [])", 'E745:') call assert_fails("let v=strchars('abc', 2)", 'E1023:') endfunc *** ../vim-8.2.2605/src/version.c 2021-03-14 18:38:50.016676652 +0100 --- src/version.c 2021-03-14 18:47:48.758749101 +0100 *************** *** 752,753 **** --- 752,755 ---- { /* Add new patch number below this line */ + /**/ + 2606, /**/ -- An easy way to determine if you have enough teamwork to be doomed is simply to measure how long it takes from the time you decide to go to lunch together until the time you actually eat. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///