[Libguestfs] [PATCH v5 2/3] mllib: modify nsplit to take optional noempty and count arguments

Tomáš Golembiovský tgolembi at redhat.com
Wed Jan 11 13:42:28 UTC 2017


Added two new optional arguments to nsplit:

* keep_empty: if set to false empty elements are not stored in the
  returned list. The default is to keep the empty elements

* count: specifies how many splits to perform; negative count
  (the default) means do as many splits as possible

Added tests for nsplit.

Signed-off-by: Tomáš Golembiovský <tgolembi at redhat.com>
---
 mllib/common_utils.ml       | 13 ++++++++++---
 mllib/common_utils.mli      | 12 ++++++++++--
 mllib/common_utils_tests.ml | 30 ++++++++++++++++++++++++++++++
 3 files changed, 50 insertions(+), 5 deletions(-)

diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml
index e9ae6a4a2..6c5df5e1c 100644
--- a/mllib/common_utils.ml
+++ b/mllib/common_utils.ml
@@ -130,15 +130,22 @@ module String = struct
       done;
       if not !r then s else Bytes.to_string b2
 
-    let rec nsplit sep str =
+    let rec nsplit ?(keep_empty = true) ?(count = -1) sep str =
       let len = length str in
       let seplen = length sep in
       let i = find str sep in
-      if i = -1 then [str]
+      if i = -1 || count = 0 then
+        if str = "" && not keep_empty then [] else [str]
       else (
         let s' = sub str 0 i in
         let s'' = sub str (i+seplen) (len-i-seplen) in
-        s' :: nsplit sep s''
+        let elem, count =
+          if s' = "" && not keep_empty then
+            [], count
+          else
+            [s'], if count > 0 then count-1 else count
+        in
+        elem @ nsplit ~keep_empty:keep_empty ~count:count sep s''
       )
 
     let split sep str =
diff --git a/mllib/common_utils.mli b/mllib/common_utils.mli
index 722e528e5..5494c018c 100644
--- a/mllib/common_utils.mli
+++ b/mllib/common_utils.mli
@@ -80,9 +80,17 @@ module String : sig
         [str] with [s2]. *)
     val replace_char : string -> char -> char -> string
     (** Replace character in string. *)
-    val nsplit : string -> string -> string list
+    val nsplit : ?keep_empty:bool -> ?count:int -> string -> string -> string list
     (** [nsplit sep str] splits [str] into multiple strings at each
-        separator [sep]. *)
+        separator [sep].
+
+        If [keep_empty] is set to false empty elements not included in the
+        returned list. By default empty elements are kept.
+
+        If [count] is specified it says how many splits to perform. I.e. the
+        returned array will have at most [count]+1 elements. Negative [count]
+        (the default) means do as many splits as possible.
+        *)
     val split : string -> string -> string * string
     (** [split sep str] splits [str] at the first occurrence of the
         separator [sep], returning the part before and the part after.
diff --git a/mllib/common_utils_tests.ml b/mllib/common_utils_tests.ml
index 77b0524c1..e30179323 100644
--- a/mllib/common_utils_tests.ml
+++ b/mllib/common_utils_tests.ml
@@ -109,6 +109,35 @@ let test_string_find ctx =
   assert_equal_int (-1) (String.find "" "baz");
   assert_equal_int (-1) (String.find "foobar" "baz")
 
+(* Test Common_utils.String.nsplit *)
+let test_string_nsplit ctx =
+  (* Basic functionality *)
+  assert_equal_stringlist [""] (String.nsplit "|" "");
+  assert_equal_stringlist ["A"] (String.nsplit "|" "A");
+  assert_equal_stringlist ["A"; "B"] (String.nsplit "|" "A|B");
+  assert_equal_stringlist ["A"; "B"; "C"] (String.nsplit "|" "A|B|C");
+  assert_equal_stringlist ["A"; "B"; "C"; "D"] (String.nsplit "|" "A|B|C|D");
+  assert_equal_stringlist [""; "A"; ""] (String.nsplit "|" "|A|");
+  assert_equal_stringlist ["A"; ""; ""; "B"] (String.nsplit "|" "A|||B");
+  assert_equal_stringlist ["A"; "B"; "C"; "D"] (String.nsplit "<>" "A<>B<>C<>D");
+
+  (* keep_empty option *)
+  assert_equal_stringlist [ ] (String.nsplit ~keep_empty:false "|" "");
+  assert_equal_stringlist ["A"] (String.nsplit ~keep_empty:false "|" "|A|");
+  assert_equal_stringlist ["A"; "B"] (String.nsplit ~keep_empty:false "|" "A|||B");
+  assert_equal_stringlist [""; "A"; ""] (String.nsplit ~keep_empty:true "|" "|A|");
+  assert_equal_stringlist ["A"; ""; ""; "B"] (String.nsplit ~keep_empty:true "|" "A|||B");
+
+  (* count option *)
+  assert_equal_stringlist ["A"; "B"; "C"; "D"] (String.nsplit ~count:(-1) "|" "A|B|C|D");
+  assert_equal_stringlist ["A|B|C|D"] (String.nsplit ~count:0 "|" "A|B|C|D");
+  assert_equal_stringlist ["A"; "B|C|D"] (String.nsplit ~count:1 "|" "A|B|C|D");
+  assert_equal_stringlist ["A"; "B"; "C|D"] (String.nsplit ~count:2 "|" "A|B|C|D");
+  assert_equal_stringlist ["A"; "B"; "C"; "D"] (String.nsplit ~count:10 "|" "A|B|C|D");
+
+  (* count and keep_empty together *)
+  assert_equal_stringlist ["A"; "B"; "|||C|D"] (String.nsplit ~keep_empty:false ~count:2 "|" "|||A||||B||||C|D")
+
 (* Test Common_utils.String.lines_split. *)
 let test_string_lines_split ctx =
   assert_equal_stringlist [""] (String.lines_split "");
@@ -135,6 +164,7 @@ let suite =
       "strings.is_prefix" >:: test_string_is_prefix;
       "strings.is_suffix" >:: test_string_is_suffix;
       "strings.find" >:: test_string_find;
+      "strings.nsplit" >:: test_string_nsplit;
       "strings.lines_split" >:: test_string_lines_split;
     ]
 
-- 
2.11.0




More information about the Libguestfs mailing list