// Small text utilities used by the line-oriented parser and matcher.
///|
fn lower_ascii(input : String) -> String {
let output : Array[Char] = []
for ch in input {
let code = ch.to_int()
if code >= 'A'.to_int() && code <= 'Z'.to_int() {
output.push((code + 32).unsafe_to_char())
} else {
output.push(ch)
}
}
String::from_array(output)
}
///|
fn strip_utf8_bom(line : String) -> String {
let chars = line.to_array()
if chars.length() > 0 && chars[0] == '\u{FEFF}' {
String::from_array(chars[1:])
} else {
line
}
}
///|
fn strip_one_trailing_cr(line : String) -> String {
if line.has_suffix("\r") {
let chars = line.to_array()
String::from_array(chars[0:chars.length() - 1])
} else {
line
}
}
///|
fn strip_comment(line : String) -> String {
match line.split_once("#") {
Some(parts) => parts.0.to_owned()
None => line
}
}
///|
fn inline_comment_count(line : String) -> Int {
if line.contains("#") {
1
} else {
0
}
}
///|
fn is_ascii_letter(ch : Char) -> Bool {
let code = ch.to_int()
(code >= 'A'.to_int() && code <= 'Z'.to_int()) ||
(code >= 'a'.to_int() && code <= 'z'.to_int())
}
///|
fn is_ascii_digit(ch : Char) -> Bool {
let code = ch.to_int()
code >= '0'.to_int() && code <= '9'.to_int()
}
///|
fn is_agent_char(ch : Char) -> Bool {
is_ascii_letter(ch) ||
is_ascii_digit(ch) ||
ch == '-' ||
ch == '_' ||
ch == '.'
}
///|
fn valid_product_token(token : String) -> Bool {
if token == "*" {
return true
}
if token.length() == 0 {
return false
}
for ch in token {
if !is_agent_char(ch) {
return false
}
}
true
}
///|
fn is_record_name_char(ch : Char) -> Bool {
is_ascii_letter(ch) || is_ascii_digit(ch) || ch == '-'
}
///|
fn valid_record_name(name : String) -> Bool {
if name.length() == 0 {
return false
}
for ch in name {
if !is_record_name_char(ch) {
return false
}
}
true
}
///|
fn contains_illegal_control(input : String) -> Bool {
for ch in input {
let code = ch.to_int()
if (code >= 0 && code < 32 && ch != '\t' && ch != '\r' && ch != '\n') ||
code == 127 {
return true
}
}
false
}
///|
fn byte_len(input : String) -> Int {
@utf8.encode(input).length()
}
///|
fn count_char(input : String, target : Char) -> Int {
let mut count = 0
for ch in input {
if ch == target {
count = count + 1
}
}
count
}
///|
fn join_strings(items : Array[String], sep : String) -> String {
let sb = StringBuilder::new()
for i, item in items {
if i > 0 {
sb.write_string(sep)
}
sb.write_string(item)
}
sb.to_string()
}
///|
fn array_contains_string(items : Array[String], value : String) -> Bool {
for item in items {
if item == value {
return true
}
}
false
}
///|
fn push_unique_string(items : Array[String], value : String) -> Bool {
if array_contains_string(items, value) {
false
} else {
items.push(value)
true
}
}
///|
pub fn json_string(input : String) -> String {
let sb = StringBuilder::new()
for ch in input {
if ch == '"' {
sb.write_string("\\\"")
} else if ch == '\\' {
sb.write_string("\\\\")
} else if ch == '\n' {
sb.write_string("\\n")
} else if ch == '\r' {
sb.write_string("\\r")
} else if ch == '\t' {
sb.write_string("\\t")
} else {
sb.write_char(ch)
}
}
sb.to_string()
}