diff --git a/vlib/builtin/string.v b/vlib/builtin/string.v index 7b79e13b7c..af81e3386d 100644 --- a/vlib/builtin/string.v +++ b/vlib/builtin/string.v @@ -2767,8 +2767,8 @@ pub fn (name string) match_glob(pattern string) bool { return true } -// is_ascii returns true if all characters belong to the US-ASCII set ([` `..`~`]) -@[inline] +// is_ascii returns true if all characters belong to the US-ASCII set ([` `..`~`]) +@[direct_array_access; inline] pub fn (s string) is_ascii() bool { for i := 0; i < s.len; i++ { if s[i] < u8(` `) || s[i] > u8(`~`) { @@ -2778,6 +2778,24 @@ pub fn (s string) is_ascii() bool { return true } +// is_identifier checks if a string is a valid identifier (starts with letter/underscore, followed by letters, digits, or underscores) +@[direct_array_access] +pub fn (s string) is_identifier() bool { + if s.len == 0 { + return false + } + if !(s[0].is_letter() || s[0] == `_`) { + return false + } + for i := 1; i < s.len; i++ { + c := s[i] + if !(c.is_letter() || c.is_digit() || c == `_`) { + return false + } + } + return true +} + // camel_to_snake convert string from camelCase to snake_case // Example: assert 'Abcd'.camel_to_snake() == 'abcd' // Example: assert 'aaBB'.camel_to_snake() == 'aa_bb' diff --git a/vlib/builtin/string_test.v b/vlib/builtin/string_test.v index f54b21502f..d8c83575ed 100644 --- a/vlib/builtin/string_test.v +++ b/vlib/builtin/string_test.v @@ -1553,6 +1553,20 @@ fn test_string_is_ascii() { assert 'a👋bc'.is_ascii() == false } +fn test_string_is_identifier() { + assert ''.is_identifier() == false + assert ' '.is_identifier() == false + assert '~~'.is_identifier() == false + assert '_Az~'.is_identifier() == false + assert '_Aö~'.is_identifier() == false + assert '👋'.is_identifier() == false + assert 'a👋bc'.is_identifier() == false + assert '9'.is_identifier() == false + assert '_9'.is_identifier() == true + assert 'a 9'.is_identifier() == false + assert 't'.is_identifier() == true +} + fn test_string_with_zero_byte_escape() { assert '\x00'.bytes() == [u8(0)] }