]> granicus.if.org Git - vim/commitdiff
patch 7.4.1730 v7.4.1730
authorBram Moolenaar <Bram@vim.org>
Thu, 14 Apr 2016 13:13:46 +0000 (15:13 +0200)
committerBram Moolenaar <Bram@vim.org>
Thu, 14 Apr 2016 13:13:46 +0000 (15:13 +0200)
Problem:    It is not easy to get a character out of a string.
Solution:   Add strgetchar() and strcharpart().

src/eval.c
src/testdir/test_expr.vim
src/version.c

index 86580450fca5fe5f4f1e3b82f86d67686a5d80a2..9dd4d84d3979c0150e118a58ad3a9adc87f64ba7 100644 (file)
@@ -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},
@@ -19550,6 +19554,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
  */
@@ -19677,6 +19721,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
  */
index 33115c7f1fe223f10c25e43a0007df8af1123616..cdaf45ee734422122421661acde7dcda88007a5f 100644 (file)
@@ -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
index 26831238bf901f3d040991456d4f1a3ca841b73f..7132e0b07200d46f18a06baeaaff653c906e7712 100644 (file)
@@ -748,6 +748,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1730,
 /**/
     1729,
 /**/