Skip to content

Commit 70ce8a1

Browse files
committed
patch 8.2.2606: strchars() defaults to counting composing characters
Problem: strchars() defaults to counting composing characters. Solution: Add strcharlen() which ignores composing characters.
1 parent 0289a09 commit 70ce8a1

5 files changed

Lines changed: 59 additions & 15 deletions

File tree

runtime/doc/eval.txt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2923,10 +2923,11 @@ str2list({expr} [, {utf8}]) List convert each character of {expr} to
29232923
ASCII/UTF8 value
29242924
str2nr({expr} [, {base} [, {quoted}]])
29252925
Number convert String to Number
2926+
strcharlen({expr}) Number character length of the String {expr}
29262927
strcharpart({str}, {start} [, {len}])
29272928
String {len} characters of {str} at
29282929
character {start}
2929-
strchars({expr} [, {skipcc}]) Number character length of the String {expr}
2930+
strchars({expr} [, {skipcc}]) Number character count of the String {expr}
29302931
strdisplaywidth({expr} [, {col}]) Number display length of the String {expr}
29312932
strftime({format} [, {time}]) String format time with a specified format
29322933
strgetchar({str}, {index}) Number get char {index} from {str}
@@ -10276,6 +10277,19 @@ str2nr({expr} [, {base} [, {quoted}]]) *str2nr()*
1027610277
Can also be used as a |method|: >
1027710278
GetText()->str2nr()
1027810279

10280+
10281+
strcharlen({expr}) *strcharlen()*
10282+
The result is a Number, which is the number of characters
10283+
in String {expr}. Composing characters are ignored.
10284+
|strchars()| can count the number of characters, counting
10285+
composing characters separately.
10286+
10287+
Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
10288+
10289+
Can also be used as a |method|: >
10290+
GetText()->strcharlen()
10291+
10292+
1027910293
strcharpart({src}, {start} [, {len}]) *strcharpart()*
1028010294
Like |strpart()| but using character index and length instead
1028110295
of byte index and length. Composing characters are counted
@@ -10288,12 +10302,15 @@ strcharpart({src}, {start} [, {len}]) *strcharpart()*
1028810302
Can also be used as a |method|: >
1028910303
GetText()->strcharpart(5)
1029010304

10305+
1029110306
strchars({expr} [, {skipcc}]) *strchars()*
1029210307
The result is a Number, which is the number of characters
1029310308
in String {expr}.
1029410309
When {skipcc} is omitted or zero, composing characters are
1029510310
counted separately.
1029610311
When {skipcc} set to 1, Composing characters are ignored.
10312+
|strcharlen()| does the same.
10313+
1029710314
Also see |strlen()|, |strdisplaywidth()| and |strwidth()|.
1029810315

1029910316
{skipcc} is only available after 7.4.755. For backward

runtime/doc/usr_41.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -611,7 +611,8 @@ String manipulation: *string-functions*
611611
stridx() first index of a short string in a long string
612612
strridx() last index of a short string in a long string
613613
strlen() length of a string in bytes
614-
strchars() length of a string in characters
614+
strcharlen() length of a string in characters
615+
strchars() number of characters in a string
615616
strwidth() size of string when displayed
616617
strdisplaywidth() size of string when displayed, deals with tabs
617618
setcellwidths() set character cell width overrides

src/evalfunc.c

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,7 @@ static void f_str2float(typval_T *argvars, typval_T *rettv);
223223
#endif
224224
static void f_str2list(typval_T *argvars, typval_T *rettv);
225225
static void f_str2nr(typval_T *argvars, typval_T *rettv);
226+
static void f_strcharlen(typval_T *argvars, typval_T *rettv);
226227
static void f_strchars(typval_T *argvars, typval_T *rettv);
227228
static void f_strgetchar(typval_T *argvars, typval_T *rettv);
228229
static void f_stridx(typval_T *argvars, typval_T *rettv);
@@ -1572,6 +1573,8 @@ static funcentry_T global_functions[] =
15721573
ret_list_number, f_str2list},
15731574
{"str2nr", 1, 3, FEARG_1, arg3_string_nr_bool,
15741575
ret_number, f_str2nr},
1576+
{"strcharlen", 1, 1, FEARG_1, NULL,
1577+
ret_number, f_strcharlen},
15751578
{"strcharpart", 2, 3, FEARG_1, NULL,
15761579
ret_string, f_strcharpart},
15771580
{"strchars", 1, 2, FEARG_1, NULL,
@@ -9236,31 +9239,45 @@ f_strlen(typval_T *argvars, typval_T *rettv)
92369239
tv_get_string(&argvars[0])));
92379240
}
92389241

9242+
static void
9243+
strchar_common(typval_T *argvars, typval_T *rettv, int skipcc)
9244+
{
9245+
char_u *s = tv_get_string(&argvars[0]);
9246+
varnumber_T len = 0;
9247+
int (*func_mb_ptr2char_adv)(char_u **pp);
9248+
9249+
func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
9250+
while (*s != NUL)
9251+
{
9252+
func_mb_ptr2char_adv(&s);
9253+
++len;
9254+
}
9255+
rettv->vval.v_number = len;
9256+
}
9257+
9258+
/*
9259+
* "strcharlen()" function
9260+
*/
9261+
static void
9262+
f_strcharlen(typval_T *argvars, typval_T *rettv)
9263+
{
9264+
strchar_common(argvars, rettv, TRUE);
9265+
}
9266+
92399267
/*
92409268
* "strchars()" function
92419269
*/
92429270
static void
92439271
f_strchars(typval_T *argvars, typval_T *rettv)
92449272
{
9245-
char_u *s = tv_get_string(&argvars[0]);
92469273
varnumber_T skipcc = FALSE;
9247-
varnumber_T len = 0;
9248-
int (*func_mb_ptr2char_adv)(char_u **pp);
92499274

92509275
if (argvars[1].v_type != VAR_UNKNOWN)
92519276
skipcc = tv_get_bool(&argvars[1]);
92529277
if (skipcc < 0 || skipcc > 1)
92539278
semsg(_(e_using_number_as_bool_nr), skipcc);
92549279
else
9255-
{
9256-
func_mb_ptr2char_adv = skipcc ? mb_ptr2char_adv : mb_cptr2char_adv;
9257-
while (*s != NUL)
9258-
{
9259-
func_mb_ptr2char_adv(&s);
9260-
++len;
9261-
}
9262-
rettv->vval.v_number = len;
9263-
}
9280+
strchar_common(argvars, rettv, skipcc);
92649281
}
92659282

92669283
/*

src/testdir/test_utf8.vim

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ func Test_visual_block_insert()
1111
bwipeout!
1212
endfunc
1313

14-
" Test for built-in function strchars()
14+
" Test for built-in functions strchars() and strcharlen()
1515
func Test_strchars()
1616
let inp = ["a", "あいa", "A\u20dd", "A\u20dd\u20dd", "\u20dd"]
1717
let exp = [[1, 1, 1], [3, 3, 3], [2, 2, 1], [3, 3, 1], [1, 1, 1]]
@@ -20,6 +20,13 @@ func Test_strchars()
2020
call assert_equal(exp[i][1], inp[i]->strchars(0))
2121
call assert_equal(exp[i][2], strchars(inp[i], 1))
2222
endfor
23+
24+
let exp = [1, 3, 1, 1, 1]
25+
for i in range(len(inp))
26+
call assert_equal(exp[i], inp[i]->strcharlen())
27+
call assert_equal(exp[i], strcharlen(inp[i]))
28+
endfor
29+
2330
call assert_fails("let v=strchars('abc', [])", 'E745:')
2431
call assert_fails("let v=strchars('abc', 2)", 'E1023:')
2532
endfunc

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -750,6 +750,8 @@ static char *(features[]) =
750750

751751
static int included_patches[] =
752752
{ /* Add new patch number below this line */
753+
/**/
754+
2606,
753755
/**/
754756
2605,
755757
/**/

0 commit comments

Comments
 (0)