///|
pub(all) struct CsvOptions {
delimiter : String
has_header : Bool
comment_prefix : String
} derive(Debug, Eq)
///|
pub fn CsvOptions::default() -> CsvOptions {
{ delimiter: ",", has_header: true, comment_prefix: "#" }
}
///|
fn meaningful_lines(text : String, comment_prefix : String) -> Array[String] {
let lines : Array[String] = []
for raw in text.split("\n") {
let line = raw.trim().to_owned()
if line != "" && !line.has_prefix(comment_prefix) {
lines.push(line)
}
}
lines
}
///|
fn parse_number(
text : StringView,
row : Int,
column : Int,
) -> Double raise @domain.ExtractionError {
@strconv.from_str(text.trim()) catch {
_ =>
raise @domain.ExtractionError::InvalidArgument(
message="invalid number at row \{row}, column \{column}: \{text}",
)
}
}
///|
/// Parse a two-column equilibrium table (`x,y`) from CSV text.
pub fn parse_equilibrium_csv(
text : String,
options? : CsvOptions = CsvOptions::default(),
extrapolation? : @interpolation.Extrapolation = @interpolation.Extrapolation::Reject,
) -> @interpolation.EquilibriumTable raise @domain.ExtractionError {
if options.delimiter == "" {
raise @domain.ExtractionError::InvalidArgument(
message="CSV delimiter cannot be empty",
)
}
let lines = meaningful_lines(text, options.comment_prefix)
let first_data_row = if options.has_header { 1 } else { 0 }
if lines.length() <= first_data_row {
raise @domain.ExtractionError::InsufficientData(
required=first_data_row + 2,
actual=lines.length(),
)
}
let points : Array[@domain.EquilibriumPoint] = []
for index in first_data_row.. Array[@domain.TieLine] raise @domain.ExtractionError {
let lines = meaningful_lines(text, options.comment_prefix)
let first_data_row = if options.has_header { 1 } else { 0 }
if lines.length() <= first_data_row {
raise @domain.ExtractionError::InsufficientData(
required=first_data_row + 1,
actual=lines.length(),
)
}
let tie_lines : Array[@domain.TieLine] = []
for index in first_data_row.. parse_number(cell, index + 1, column + 1)
]
tie_lines.push(
@domain.TieLine::new(
raffinate=@domain.TernaryComposition::new(
carrier=values[0],
solute=values[1],
solvent=values[2],
),
extract=@domain.TernaryComposition::new(
carrier=values[3],
solute=values[4],
solvent=values[5],
),
),
)
}
tie_lines
}