diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-04-14 15:13:46 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-04-14 15:13:46 +0200 |
commit | 58de0e2dcc1f2d251b74892a06d71a14973f3187 (patch) | |
tree | 73357af1942325ac46de5990a06d872d1e626118 | |
parent | 6244a0fc29163ba1c734f92b55a89e01e6cf2a67 (diff) | |
download | vim-git-58de0e2dcc1f2d251b74892a06d71a14973f3187.tar.gz |
patch 7.4.1730v7.4.1730
Problem: It is not easy to get a character out of a string.
Solution: Add strgetchar() and strcharpart().
-rw-r--r-- | src/eval.c | 109 | ||||
-rw-r--r-- | src/testdir/test_expr.vim | 47 | ||||
-rw-r--r-- | src/version.c | 2 |
3 files changed, 158 insertions, 0 deletions
diff --git a/src/eval.c b/src/eval.c index 86580450f..9dd4d84d3 100644 --- a/src/eval.c +++ b/src/eval.c @@ -779,9 +779,11 @@ static void f_strchars(typval_T *argvars, typval_T *rettv); #ifdef HAVE_STRFTIME static void f_strftime(typval_T *argvars, typval_T *rettv); #endif +static void f_strgetchar(typval_T *argvars, typval_T *rettv); static void f_stridx(typval_T *argvars, typval_T *rettv); static void f_string(typval_T *argvars, typval_T *rettv); static void f_strlen(typval_T *argvars, typval_T *rettv); +static void f_strcharpart(typval_T *argvars, typval_T *rettv); static void f_strpart(typval_T *argvars, typval_T *rettv); static void f_strridx(typval_T *argvars, typval_T *rettv); static void f_strtrans(typval_T *argvars, typval_T *rettv); @@ -8635,11 +8637,13 @@ static struct fst {"str2float", 1, 1, f_str2float}, #endif {"str2nr", 1, 2, f_str2nr}, + {"strcharpart", 2, 3, f_strcharpart}, {"strchars", 1, 2, f_strchars}, {"strdisplaywidth", 1, 2, f_strdisplaywidth}, #ifdef HAVE_STRFTIME {"strftime", 1, 2, f_strftime}, #endif + {"strgetchar", 2, 2, f_strgetchar}, {"stridx", 2, 3, f_stridx}, {"string", 1, 1, f_string}, {"strlen", 1, 1, f_strlen}, @@ -19551,6 +19555,46 @@ f_strftime(typval_T *argvars, typval_T *rettv) #endif /* + * "strgetchar()" function + */ + static void +f_strgetchar(typval_T *argvars, typval_T *rettv) +{ + char_u *str; + int len; + int error = FALSE; + int charidx; + + rettv->vval.v_number = -1; + str = get_tv_string_chk(&argvars[0]); + if (str == NULL) + return; + len = (int)STRLEN(str); + charidx = get_tv_number_chk(&argvars[1], &error); + if (error) + return; +#ifdef FEAT_MBYTE + { + int byteidx = 0; + + while (charidx >= 0 && byteidx < len) + { + if (charidx == 0) + { + rettv->vval.v_number = mb_ptr2char(str + byteidx); + break; + } + --charidx; + byteidx += mb_char2len(str[byteidx]); + } + } +#else + if (charidx < len) + rettv->vval.v_number = str[charidx]; +#endif +} + +/* * "stridx()" function */ static void @@ -19678,6 +19722,71 @@ f_strwidth(typval_T *argvars, typval_T *rettv) } /* + * "strcharpart()" function + */ + static void +f_strcharpart(typval_T *argvars, typval_T *rettv) +{ +#ifdef FEAT_MBYTE + char_u *p; + int nchar; + int nbyte = 0; + int charlen; + int len = 0; + int slen; + int error = FALSE; + + p = get_tv_string(&argvars[0]); + slen = (int)STRLEN(p); + + nchar = get_tv_number_chk(&argvars[1], &error); + if (!error) + { + if (nchar > 0) + while (nchar > 0 && nbyte < slen) + { + nbyte += mb_char2len(p[nbyte]); + --nchar; + } + else + nbyte = nchar; + if (argvars[2].v_type != VAR_UNKNOWN) + { + charlen = get_tv_number(&argvars[2]); + while (charlen > 0 && nbyte + len < slen) + { + len += mb_char2len(p[nbyte + len]); + --charlen; + } + } + else + len = slen - nbyte; /* default: all bytes that are available. */ + } + + /* + * Only return the overlap between the specified part and the actual + * string. + */ + if (nbyte < 0) + { + len += nbyte; + nbyte = 0; + } + else if (nbyte > slen) + nbyte = slen; + if (len < 0) + len = 0; + else if (nbyte + len > slen) + len = slen - nbyte; + + rettv->v_type = VAR_STRING; + rettv->vval.v_string = vim_strnsave(p + nbyte, len); +#else + f_strpart(argvars, rettv); +#endif +} + +/* * "strpart()" function */ static void diff --git a/src/testdir/test_expr.vim b/src/testdir/test_expr.vim index 33115c7f1..cdaf45ee7 100644 --- a/src/testdir/test_expr.vim +++ b/src/testdir/test_expr.vim @@ -50,3 +50,50 @@ func Test_dict() call assert_equal('none', d['']) call assert_equal('aaa', d['a']) endfunc + +func Test_strgetchar() + call assert_equal(char2nr('a'), strgetchar('axb', 0)) + call assert_equal(char2nr('x'), strgetchar('axb', 1)) + call assert_equal(char2nr('b'), strgetchar('axb', 2)) + + call assert_equal(-1, strgetchar('axb', -1)) + call assert_equal(-1, strgetchar('axb', 3)) + call assert_equal(-1, strgetchar('', 0)) + + if !has('multi_byte') + return + endif + + call assert_equal(char2nr('á'), strgetchar('áxb', 0)) + call assert_equal(char2nr('x'), strgetchar('áxb', 1)) + + call assert_equal(char2nr('a'), strgetchar('àxb', 0)) + call assert_equal(char2nr('̀'), strgetchar('àxb', 1)) + call assert_equal(char2nr('x'), strgetchar('àxb', 2)) +endfunc + +func Test_strcharpart() + call assert_equal('a', strcharpart('axb', 0, 1)) + call assert_equal('x', strcharpart('axb', 1, 1)) + call assert_equal('b', strcharpart('axb', 2, 1)) + call assert_equal('xb', strcharpart('axb', 1)) + + call assert_equal('', strcharpart('axb', 1, 0)) + call assert_equal('', strcharpart('axb', 1, -1)) + call assert_equal('', strcharpart('axb', -1, 1)) + call assert_equal('', strcharpart('axb', -2, 2)) + + call assert_equal('a', strcharpart('axb', -1, 2)) + + if !has('multi_byte') + return + endif + + call assert_equal('áxb', strcharpart('áxb', 0)) + call assert_equal('á', strcharpart('áxb', 0, 1)) + call assert_equal('x', strcharpart('áxb', 1, 1)) + + call assert_equal('a', strcharpart('àxb', 0, 1)) + call assert_equal('̀', strcharpart('àxb', 1, 1)) + call assert_equal('x', strcharpart('àxb', 2, 1)) +endfunc diff --git a/src/version.c b/src/version.c index 26831238b..7132e0b07 100644 --- a/src/version.c +++ b/src/version.c @@ -749,6 +749,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1730, +/**/ 1729, /**/ 1728, |