changeset 8887:8bf855dea79e v7.4.1730

commit https://github.com/vim/vim/commit/58de0e2dcc1f2d251b74892a06d71a14973f3187 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Apr 14 15:13:46 2016 +0200 patch 7.4.1730 Problem: It is not easy to get a character out of a string. Solution: Add strgetchar() and strcharpart().
author Christian Brabandt <cb@256bit.org>
date Thu, 14 Apr 2016 15:15:05 +0200
parents 9954d0cd1e87
children a63c61b66a49
files src/eval.c src/testdir/test_expr.vim src/version.c
diffstat 3 files changed, 158 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/src/eval.c
+++ b/src/eval.c
@@ -779,9 +779,11 @@ static void f_strchars(typval_T *argvars
 #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 *
 #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 *
 }
 
 /*
+ * "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
--- 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
--- 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,