Char.mem tells you if a byte is a member of a string.
String.span and String.cspan are like the C functions strspn and
strcspn.
---
common/mlstdutils/std_utils.ml | 27 +++++++++++++++++++++++++++
common/mlstdutils/std_utils.mli | 12 ++++++++++++
common/mlstdutils/std_utils_tests.ml | 21 +++++++++++++++++++++
3 files changed, 60 insertions(+)
diff --git a/common/mlstdutils/std_utils.ml b/common/mlstdutils/std_utils.ml
index f545c6f7a..a153ceb7f 100644
--- a/common/mlstdutils/std_utils.ml
+++ b/common/mlstdutils/std_utils.ml
@@ -74,6 +74,15 @@ module Char = struct
| 'e' | 'E' -> 14
| 'f' | 'F' -> 15
| _ -> -1
+
+ let mem c str =
+ let len = String.length str in
+ let rec loop i =
+ if i >= len then false
+ else if String.unsafe_get str i = c then true
+ else loop (i+1)
+ in
+ loop 0
end
module String = struct
@@ -246,6 +255,24 @@ module String = struct
List.map f (explode str)
let spaces n = String.make n ' '
+
+ let span str accept =
+ let len = String.length str in
+ let rec loop i =
+ if i >= len then len
+ else if Char.mem (String.unsafe_get str i) accept then loop (i+1)
+ else i
+ in
+ loop 0
+
+ let cspan str reject =
+ let len = String.length str in
+ let rec loop i =
+ if i >= len then len
+ else if Char.mem (String.unsafe_get str i) reject then i
+ else loop (i+1)
+ in
+ loop 0
end
let (//) = Filename.concat
diff --git a/common/mlstdutils/std_utils.mli b/common/mlstdutils/std_utils.mli
index 686d4193f..b61b9bb02 100644
--- a/common/mlstdutils/std_utils.mli
+++ b/common/mlstdutils/std_utils.mli
@@ -41,6 +41,9 @@ module Char : sig
val hexdigit : char -> int
(** Return the value of a hex digit. If the char is not in
the set [[0-9a-fA-F]] then this returns [-1]. *)
+
+ val mem : char -> string -> bool
+ (** [mem c str] returns true if the byte [c] is contained in [str]. *)
end
(** Override the Char module from stdlib. *)
@@ -109,6 +112,15 @@ module String : sig
(** Explode string, then map function over the characters. *)
val spaces : int -> string
(** [spaces n] creates a string of n spaces. *)
+ val span : string -> string -> int
+ val cspan : string -> string -> int
+ (** [span str accept] returns the length in bytes of the initial
+ segment of [str] which contains only bytes in [accept].
+
+ [cspan str reject] returns the length in bytes of the initial
+ segment of [str] which contains only bytes {!i not} in [reject].
+
+ These work exactly like the C functions [strspn] and [strcspn]. *)
end
(** Override the String module from stdlib. *)
diff --git a/common/mlstdutils/std_utils_tests.ml b/common/mlstdutils/std_utils_tests.ml
index 6bc74fb63..2789766c6 100644
--- a/common/mlstdutils/std_utils_tests.ml
+++ b/common/mlstdutils/std_utils_tests.ml
@@ -50,6 +50,14 @@ and test_swap int_of_x x_of_int i s =
assert_equal_int64 i (int_of_x s);
assert_equal_string s (x_of_int i)
+(* Test Std_utils.Char.mem. *)
+let test_char_mem ctx =
+ assert_bool "Char.mem" (Char.mem 'a' "abc");
+ assert_bool "Char.mem" (Char.mem 'b' "abc");
+ assert_bool "Char.mem" (Char.mem 'c' "abc");
+ assert_bool "Char.mem" (not (Char.mem 'd' "abc"));
+ assert_bool "Char.mem" (not (Char.mem 'a' ""))
+
(* Test Std_utils.String.is_prefix. *)
let test_string_is_prefix ctx =
assert_bool "String.is_prefix,," (String.is_prefix ""
"");
@@ -91,16 +99,29 @@ let test_string_lines_split ctx =
assert_equal_stringlist ["A\nB"; ""] (String.lines_split
"A\\\nB\n");
assert_equal_stringlist ["A\nB\n"] (String.lines_split
"A\\\nB\\\n")
+(* Test Std_utils.String.span and cspan. *)
+let test_string_span ctx =
+ assert_equal_int 3 (String.span "aaabb" "a");
+ assert_equal_int 3 (String.span "aaaba" "a");
+ assert_equal_int 3 (String.span "aba" "ab");
+ assert_equal_int 0 (String.span "" "ab");
+ assert_equal_int 3 (String.cspan "defab" "ab");
+ assert_equal_int 3 (String.cspan "defba" "ab");
+ assert_equal_int 3 (String.cspan "def" "ab");
+ assert_equal_int 0 (String.cspan "" "ab")
+
(* Suites declaration. *)
let suite =
"mllib Std_utils" >:::
[
"subdirectory" >:: test_subdirectory;
"numeric.byteswap" >:: test_byteswap;
+ "char.mem" >:: test_char_mem;
"strings.is_prefix" >:: test_string_is_prefix;
"strings.is_suffix" >:: test_string_is_suffix;
"strings.find" >:: test_string_find;
"strings.lines_split" >:: test_string_lines_split;
+ "strings.span" >:: test_string_span;
]
let () =
--
2.13.0