1
0
forked from aniani/vim

patch 8.2.2606: strchars() defaults to counting composing characters

Problem:    strchars() defaults to counting composing characters.
Solution:   Add strcharlen() which ignores composing characters.
This commit is contained in:
Bram Moolenaar
2021-03-14 19:02:09 +01:00
parent 0289a093a4
commit 70ce8a1561
5 changed files with 59 additions and 15 deletions

View File

@@ -2923,10 +2923,11 @@ str2list({expr} [, {utf8}]) List convert each character of {expr} to
ASCII/UTF8 value ASCII/UTF8 value
str2nr({expr} [, {base} [, {quoted}]]) str2nr({expr} [, {base} [, {quoted}]])
Number convert String to Number Number convert String to Number
strcharlen({expr}) Number character length of the String {expr}
strcharpart({str}, {start} [, {len}]) strcharpart({str}, {start} [, {len}])
String {len} characters of {str} at String {len} characters of {str} at
character {start} character {start}
strchars({expr} [, {skipcc}]) Number character length of the String {expr} strchars({expr} [, {skipcc}]) Number character count of the String {expr}
strdisplaywidth({expr} [, {col}]) Number display 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 strftime({format} [, {time}]) String format time with a specified format
strgetchar({str}, {index}) Number get char {index} from {str} strgetchar({str}, {index}) Number get char {index} from {str}
@@ -10276,6 +10277,19 @@ str2nr({expr} [, {base} [, {quoted}]]) *str2nr()*
Can also be used as a |method|: > Can also be used as a |method|: >
GetText()->str2nr() 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()* strcharpart({src}, {start} [, {len}]) *strcharpart()*
Like |strpart()| but using character index and length instead Like |strpart()| but using character index and length instead
of byte index and length. Composing characters are counted of byte index and length. Composing characters are counted
@@ -10288,12 +10302,15 @@ strcharpart({src}, {start} [, {len}]) *strcharpart()*
Can also be used as a |method|: > Can also be used as a |method|: >
GetText()->strcharpart(5) GetText()->strcharpart(5)
strchars({expr} [, {skipcc}]) *strchars()* strchars({expr} [, {skipcc}]) *strchars()*
The result is a Number, which is the number of characters The result is a Number, which is the number of characters
in String {expr}. in String {expr}.
When {skipcc} is omitted or zero, composing characters are When {skipcc} is omitted or zero, composing characters are
counted separately. counted separately.
When {skipcc} set to 1, Composing characters are ignored. When {skipcc} set to 1, Composing characters are ignored.
|strcharlen()| does the same.
Also see |strlen()|, |strdisplaywidth()| and |strwidth()|. Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
{skipcc} is only available after 7.4.755. For backward {skipcc} is only available after 7.4.755. For backward

View File

@@ -611,7 +611,8 @@ String manipulation: *string-functions*
stridx() first index of a short string in a long string stridx() first index of a short string in a long string
strridx() last 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 strlen() length of a string in bytes
strchars() length of a string in characters strcharlen() length of a string in characters
strchars() number of characters in a string
strwidth() size of string when displayed strwidth() size of string when displayed
strdisplaywidth() size of string when displayed, deals with tabs strdisplaywidth() size of string when displayed, deals with tabs
setcellwidths() set character cell width overrides setcellwidths() set character cell width overrides

View File

@@ -223,6 +223,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv);
#endif #endif
static void f_str2list(typval_T *argvars, typval_T *rettv); static void f_str2list(typval_T *argvars, typval_T *rettv);
static void f_str2nr(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_strchars(typval_T *argvars, typval_T *rettv);
static void f_strgetchar(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); static void f_stridx(typval_T *argvars, typval_T *rettv);
@@ -1572,6 +1573,8 @@ static funcentry_T global_functions[] =
ret_list_number, f_str2list}, ret_list_number, f_str2list},
{"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool, {"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool,
ret_number, f_str2nr}, ret_number, f_str2nr},
{"strcharlen", 1, 1, FEARG_1, NULL,
ret_number, f_strcharlen},
{"strcharpart", 2, 3, FEARG_1, NULL, {"strcharpart", 2, 3, FEARG_1, NULL,
ret_string, f_strcharpart}, ret_string, f_strcharpart},
{"strchars", 1, 2, FEARG_1, NULL, {"strchars", 1, 2, FEARG_1, NULL,
@@ -9236,31 +9239,45 @@ f_strlen(typval_T *argvars, typval_T *rettv)
tv_get_string(&argvars[0]))); 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 * "strchars()" function
*/ */
static void static void
f_strchars(typval_T *argvars, typval_T *rettv) f_strchars(typval_T *argvars, typval_T *rettv)
{ {
char_u *s = tv_get_string(&argvars[0]);
varnumber_T skipcc = FALSE; varnumber_T skipcc = FALSE;
varnumber_T len = 0;
int (*func_mb_ptr2char_adv)(char_u **pp);
if (argvars[1].v_type != VAR_UNKNOWN) if (argvars[1].v_type != VAR_UNKNOWN)
skipcc = tv_get_bool(&argvars[1]); skipcc = tv_get_bool(&argvars[1]);
if (skipcc < 0 || skipcc > 1) if (skipcc < 0 || skipcc > 1)
semsg(_(e_using_number_as_bool_nr), skipcc); semsg(_(e_using_number_as_bool_nr), skipcc);
else else
{ strchar_common(argvars, rettv, skipcc);
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;
}
} }
/* /*

View File

@@ -11,7 +11,7 @@ func Test_visual_block_insert()
bwipeout! bwipeout!
endfunc endfunc
" Test for built-in function strchars() " Test for built-in functions strchars() and strcharlen()
func Test_strchars() func Test_strchars()
let inp = ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"] 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]] let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]]
@@ -20,6 +20,13 @@ func Test_strchars()
call assert_equal(exp[i][1], inp[i]->strchars(0)) call assert_equal(exp[i][1], inp[i]->strchars(0))
call assert_equal(exp[i][2], strchars(inp[i], 1)) call assert_equal(exp[i][2], strchars(inp[i], 1))
endfor 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', [])", 'E745:')
call assert_fails("let v=strchars('abc', 2)", 'E1023:') call assert_fails("let v=strchars('abc', 2)", 'E1023:')
endfunc endfunc

View File

@@ -750,6 +750,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
2606,
/**/ /**/
2605, 2605,
/**/ /**/