diff --git a/src/core/CCChar.ml b/src/core/CCChar.ml index 5936830a..402f886e 100644 --- a/src/core/CCChar.ml +++ b/src/core/CCChar.ml @@ -23,3 +23,12 @@ module Infix = struct end include Infix + +let is_uppercase_ascii c = c > '\064' && c < '\091' +let is_lowercase_ascii c = c > '\096' && c < '\123' + +let is_letter_ascii c = + (is_lowercase_ascii [@inlined]) c || (is_uppercase_ascii [@inlined]) c + +let is_digit_ascii c = c > '\047' && c < '\058' +let is_whitespace_ascii c = c = '\032' || (c > '\008' && c < '\014') diff --git a/src/core/CCChar.mli b/src/core/CCChar.mli index d18eb48e..34dc9a81 100644 --- a/src/core/CCChar.mli +++ b/src/core/CCChar.mli @@ -40,6 +40,32 @@ val pp_buf : Buffer.t -> t -> unit val pp : Format.formatter -> t -> unit (** Renamed from [print] since 2.0. *) +val is_uppercase_ascii : t -> bool +(** [is_uppercase_ascii c] is true exactly when [c] is an + uppercase ASCII character, i.e. ['\064'] < [c] < ['\091']. + @since 3.16 *) + +val is_lowercase_ascii : t -> bool +(** [is_lowercase_ascii c] is true exactly when [c] is a + lowercase ASCII character, i.e. ['\096'] < [c] < ['\123']. + @since 3.16 *) + +val is_letter_ascii : t -> bool +(** [is_letter_ascii c] is true exactly when [c] is an ASCII + letter, i.e. [is_uppercase_ascii c || is_lowercase_ascii c]. + @since 3.16 *) + +val is_digit_ascii : t -> bool +(** [is_digit_ascii c] is true exactly when [c] is an + ASCII digit, i.e. ['\047'] < [c] < ['\058']. + @since 3.16 *) + +val is_whitespace_ascii : t -> bool +(** [is_whitespace_ascii c] is true exactly when [c] is an ASCII + whitespace character as defined by Unicode, i.e. either [c = ' '] + or ['\008'] < [c] < ['\014']. + @since 3.16 *) + (** {2 Infix Operators} @since 3.3 *) diff --git a/tests/core/t_char.ml b/tests/core/t_char.ml index d8c5d971..665f4f3f 100644 --- a/tests/core/t_char.ml +++ b/tests/core/t_char.ml @@ -8,3 +8,76 @@ eq None (of_int 257);; q (Q.string_of_size (Q.Gen.return 1)) (fun s -> Stdlib.( = ) (to_string s.[0]) s) +;; + +q (Q.int_range 65 90 |> Q.map Char.chr) CCChar.is_uppercase_ascii;; + +q + (Q.int_range 0 64 |> Q.map Char.chr) + (fun c -> not @@ CCChar.is_uppercase_ascii c) +;; + +q + (Q.int_range 91 127 |> Q.map Char.chr) + (fun c -> not @@ CCChar.is_uppercase_ascii c) +;; + +q (Q.int_range 97 122 |> Q.map Char.chr) CCChar.is_lowercase_ascii;; + +q + (Q.int_range 0 96 |> Q.map Char.chr) + (fun c -> not @@ CCChar.is_lowercase_ascii c) +;; + +q + (Q.int_range 123 127 |> Q.map Char.chr) + (fun c -> not @@ CCChar.is_lowercase_ascii c) +;; + +q (Q.int_range 48 57 |> Q.map Char.chr) CCChar.is_digit_ascii;; +q (Q.int_range 0 47 |> Q.map Char.chr) (fun c -> not @@ CCChar.is_digit_ascii c) +;; + +q + (Q.int_range 58 127 |> Q.map Char.chr) + (fun c -> not @@ CCChar.is_digit_ascii c) +;; + +eq true + (Stdlib.List.for_all CCChar.is_whitespace_ascii + [ '\n'; '\t'; ' '; '\010'; '\011'; '\012'; '\013' ]) +;; + +eq false + (Stdlib.List.exists CCChar.is_whitespace_ascii + [ + 'H'; + 'e'; + 'l'; + 'l'; + 'o'; + '!'; + '-'; + '-'; + 'N'; + 'O'; + 't'; + 'h'; + 'i'; + 'n'; + 'a'; + '\055'; + 'k'; + 'a'; + 'g'; + '$'; + '$'; + '$'; + '%'; + '^'; + 'b'; + 'c'; + 'h'; + '\008'; + 'h'; + ])