///|
pub fn codec_escape_description(value : String) -> String {
let first = value.replace(old="\\"[:], new="\\\\"[:])
let second = first.replace(old="\""[:], new="\\\""[:])
let third = second.replace(old="\n"[:], new="\\n"[:])
third.replace(old=","[:], new="\\,"[:])
}
///|
pub fn codec_unescape_description(value : String) -> String {
let builder = StringBuilder()
let mut escaped = false
for ch in value {
if escaped {
match ch {
'n' => builder.write_char('\n')
_ => builder.write_char(ch)
}
escaped = false
} else if ch == '\\' {
escaped = true
} else {
builder.write_char(ch)
}
}
if escaped {
builder.write_char('\\')
}
builder.to_string()
}
///|
pub fn codec_quote(value : String) -> String {
"\"\{codec_escape_description(value)}\""
}
///|
pub fn codec_unquote(value : String) -> String {
if value.length() >= 2 && value.has_prefix("\"") && value.has_suffix("\"") {
codec_unescape_description(
value.unsafe_substring(start=1, end=value.length() - 1),
)
} else {
value
}
}
///|
pub fn codec_split_escaped(value : String, sep : Char) -> Array[String] {
let values : Array[String] = []
let mut current = StringBuilder()
let mut escaped = false
for ch in value {
if escaped {
current.write_char(ch)
escaped = false
} else if ch == '\\' {
escaped = true
} else if ch == sep {
values.push(current.to_string())
current = StringBuilder()
} else {
current.write_char(ch)
}
}
if escaped {
current.write_char('\\')
}
values.push(current.to_string())
values
}
///|
pub fn codec_join_escaped(values : Array[String], sep : Char) -> String {
values
.map(fn(value) { value.replace(old="\\"[:], new="\\\\"[:]) })
.join(sep.to_string())
}
///|
pub fn codec_is_missing(value : String) -> Bool {
value == "." || value == ""
}
///|
pub fn codec_normalize_missing(value : String) -> String {
if codec_is_missing(value) {
"."
} else {
value
}
}
///|
pub fn codec_parse_bool(value : String) -> Bool? {
match value {
"true" | "1" | "yes" => Some(true)
"false" | "0" | "no" => Some(false)
_ => None
}
}
///|
pub fn codec_format_bool(value : Bool) -> String {
if value {
"true"
} else {
"false"
}
}
///|
pub fn codec_parse_int_list(value : String) -> Array[Int?] {
codec_split_escaped(value, ',').map(fn(item) { parse_codec_int(item) })
}
///|
fn parse_codec_int(value : String) -> Int? {
if codec_is_missing(value) {
None
} else {
let mut total = 0
for ch in value {
if ch < '0' || ch > '9' {
return None
}
total = total * 10 + ch.to_int() - '0'.to_int()
}
Some(total)
}
}
///|
pub fn codec_format_int_list(values : Array[Int?]) -> String {
values
.map(fn(value) {
match value {
Some(n) => n.to_string()
None => "."
}
})
.join(",")
}
///|
pub fn codec_parse_float_list(value : String) -> Array[Double?] {
codec_split_escaped(value, ',').map(fn(item) {
if codec_is_missing(item) {
None
} else {
Some(@string.parse_double(item[:])) catch {
_ => None
}
}
})
}
///|
pub fn codec_format_float_list(values : Array[Double?]) -> String {
values
.map(fn(value) {
match value {
Some(n) => n.to_string()
None => "."
}
})
.join(",")
}
///|
pub fn codec_pad(
values : Array[String],
width : Int,
filler : String,
) -> Array[String] {
let output = values
while output.length() < width {
output.push(filler)
}
output
}
///|
pub fn codec_truncate(values : Array[String], width : Int) -> Array[String] {
if width <= 0 {
[]
} else if values.length() <= width {
values
} else {
values[:width].to_owned()
}
}
///|
pub fn codec_join_nonempty(values : Array[String], sep : String) -> String {
values.filter(fn(value) { value != "" }).join(sep)
}