Compare commits

...

6 Commits

Author SHA1 Message Date
Juhani Krekelä 5d8462c6e4 Add more ways to spell square mile 2023-05-29 22:05:08 +03:00
Juhani Krekelä 8060f79067 Add more ways to spell square feet 2023-05-29 22:03:08 +03:00
Juhani Krekelä e6ec05323f Add more ways to spell square inches 2023-05-29 21:58:29 +03:00
Juhani Krekelä c81ebb80df Add more ways to spell degrees Fahrenheit 2023-05-29 21:52:34 +03:00
Juhani Krekelä 5335e141a4 Allow units to contain nubers after a caret 2023-05-29 21:48:45 +03:00
Juhani Krekelä fbbafcd2ec Allow units to contain spaces 2023-05-29 21:43:02 +03:00
1 changed files with 132 additions and 18 deletions

View File

@ -98,25 +98,65 @@ fn parse_unit(input: String) -> Result<NonMetric, ParseError> {
"st" => Ok(NonMetric::Stone), "st" => Ok(NonMetric::Stone),
// Temperature // Temperature
"degree Fahrenheit" => Ok(NonMetric::Fahrenheit),
"degrees Fahrenheit" => Ok(NonMetric::Fahrenheit),
"degree fahrenheit" => Ok(NonMetric::Fahrenheit),
"degrees fahrenheit" => Ok(NonMetric::Fahrenheit),
"Fahrenheit" => Ok(NonMetric::Fahrenheit),
"fahrenheit" => Ok(NonMetric::Fahrenheit),
"°F" => Ok(NonMetric::Fahrenheit), "°F" => Ok(NonMetric::Fahrenheit),
"F" => Ok(NonMetric::Fahrenheit), "F" => Ok(NonMetric::Fahrenheit),
// Area // Area
"square inch" => Ok(NonMetric::SquareInch),
"square inches" => Ok(NonMetric::SquareInch),
"square in" => Ok(NonMetric::SquareInch),
"sq inch" => Ok(NonMetric::SquareInch),
"sq inches" => Ok(NonMetric::SquareInch),
"sq in" => Ok(NonMetric::SquareInch),
"inch²" => Ok(NonMetric::SquareInch), "inch²" => Ok(NonMetric::SquareInch),
"inches²" => Ok(NonMetric::SquareInch), "inches²" => Ok(NonMetric::SquareInch),
"in²" => Ok(NonMetric::SquareInch), "in²" => Ok(NonMetric::SquareInch),
"\"²" => Ok(NonMetric::SquareInch),
"″²" => Ok(NonMetric::SquareInch),
"inch^2" => Ok(NonMetric::SquareInch),
"inches^2" => Ok(NonMetric::SquareInch),
"in^2" => Ok(NonMetric::SquareInch),
"\"^2" => Ok(NonMetric::SquareInch),
"square foot" => Ok(NonMetric::SquareFoot),
"square feet" => Ok(NonMetric::SquareFoot),
"square ft" => Ok(NonMetric::SquareFoot),
"sq foot" => Ok(NonMetric::SquareFoot),
"sq feet" => Ok(NonMetric::SquareFoot),
"sq ft" => Ok(NonMetric::SquareFoot),
"foot²" => Ok(NonMetric::SquareFoot), "foot²" => Ok(NonMetric::SquareFoot),
"feet²" => Ok(NonMetric::SquareFoot), "feet²" => Ok(NonMetric::SquareFoot),
"ft²" => Ok(NonMetric::SquareFoot), "ft²" => Ok(NonMetric::SquareFoot),
"" => Ok(NonMetric::SquareFoot),
"′²" => Ok(NonMetric::SquareFoot),
"foot^2" => Ok(NonMetric::SquareFoot),
"feet^2" => Ok(NonMetric::SquareFoot),
"ft^2" => Ok(NonMetric::SquareFoot),
"'^2" => Ok(NonMetric::SquareFoot),
"sf" => Ok(NonMetric::SquareFoot),
"acre" => Ok(NonMetric::Acre), "acre" => Ok(NonMetric::Acre),
"acres" => Ok(NonMetric::Acre), "acres" => Ok(NonMetric::Acre),
"ac" => Ok(NonMetric::Acre), "ac" => Ok(NonMetric::Acre),
"square mile" => Ok(NonMetric::SquareMile),
"square miles" => Ok(NonMetric::SquareMile),
"square mi" => Ok(NonMetric::SquareMile),
"sq mile" => Ok(NonMetric::SquareMile),
"sq miles" => Ok(NonMetric::SquareMile),
"sq mi" => Ok(NonMetric::SquareMile),
"mile²" => Ok(NonMetric::SquareMile), "mile²" => Ok(NonMetric::SquareMile),
"miles²" => Ok(NonMetric::SquareMile), "miles²" => Ok(NonMetric::SquareMile),
"mi²" => Ok(NonMetric::SquareMile), "mi²" => Ok(NonMetric::SquareMile),
"mile^2" => Ok(NonMetric::SquareMile),
"miles^2" => Ok(NonMetric::SquareMile),
"mi^2" => Ok(NonMetric::SquareMile),
_ => Err(ParseError::UnknownUnit(input)), _ => Err(ParseError::UnknownUnit(input)),
} }
@ -131,7 +171,7 @@ enum Token {
enum TokState { enum TokState {
Neutral, Neutral,
Number, Number,
Unit, Unit(bool),
} }
fn tokenize(input: &str) -> Vec<Token> { fn tokenize(input: &str) -> Vec<Token> {
@ -147,7 +187,7 @@ fn tokenize(input: &str) -> Vec<Token> {
state = TokState::Number; state = TokState::Number;
} else if !c.is_whitespace() { } else if !c.is_whitespace() {
token.push(c); token.push(c);
state = TokState::Unit; state = TokState::Unit(false);
} }
} }
TokState::Number => { TokState::Number => {
@ -157,23 +197,25 @@ fn tokenize(input: &str) -> Vec<Token> {
token.push(c); token.push(c);
} else { } else {
tokens.push(Token::Number(token.trim().to_string())); tokens.push(Token::Number(token.trim().to_string()));
state = TokState::Unit; state = TokState::Unit(false);
token = String::new(); token = String::new();
token.push(c); token.push(c);
} }
} }
TokState::Unit => { TokState::Unit(after_caret) => {
if c.is_ascii_digit() || c == '-' { if !after_caret && (c.is_ascii_digit() || c == '-') {
tokens.push(Token::Unit(token)); tokens.push(Token::Unit(token.trim().to_string()));
state = TokState::Number; state = TokState::Number;
token = String::new(); token = String::new();
token.push(c); token.push(c);
} else if !c.is_whitespace() { } else if c == '^' {
token.push(c); token.push(c);
state = TokState::Unit(true);
} else if c.is_whitespace() {
token.push(c);
state = TokState::Unit(false);
} else { } else {
tokens.push(Token::Unit(token)); token.push(c);
state = TokState::Neutral;
token = String::new();
} }
} }
} }
@ -182,7 +224,7 @@ fn tokenize(input: &str) -> Vec<Token> {
match state { match state {
TokState::Neutral => { assert!(token.len() == 0); } TokState::Neutral => { assert!(token.len() == 0); }
TokState::Number => { tokens.push(Token::Number(token.trim().to_string())); } TokState::Number => { tokens.push(Token::Number(token.trim().to_string())); }
TokState::Unit => { tokens.push(Token::Unit(token)); } TokState::Unit(_) => { tokens.push(Token::Unit(token.trim().to_string())); }
} }
tokens tokens
@ -263,25 +305,65 @@ mod test {
assert_eq!(parse_unit("st".to_string()), Ok(NonMetric::Stone)); assert_eq!(parse_unit("st".to_string()), Ok(NonMetric::Stone));
// Temperature // Temperature
assert_eq!(parse_unit("degree Fahrenheit".to_string()), Ok(NonMetric::Fahrenheit));
assert_eq!(parse_unit("degrees Fahrenheit".to_string()), Ok(NonMetric::Fahrenheit));
assert_eq!(parse_unit("degree fahrenheit".to_string()), Ok(NonMetric::Fahrenheit));
assert_eq!(parse_unit("degrees fahrenheit".to_string()), Ok(NonMetric::Fahrenheit));
assert_eq!(parse_unit("Fahrenheit".to_string()), Ok(NonMetric::Fahrenheit));
assert_eq!(parse_unit("fahrenheit".to_string()), Ok(NonMetric::Fahrenheit));
assert_eq!(parse_unit("°F".to_string()), Ok(NonMetric::Fahrenheit)); assert_eq!(parse_unit("°F".to_string()), Ok(NonMetric::Fahrenheit));
assert_eq!(parse_unit("F".to_string()), Ok(NonMetric::Fahrenheit)); assert_eq!(parse_unit("F".to_string()), Ok(NonMetric::Fahrenheit));
// Area // Area
assert_eq!(parse_unit("square inch".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("square inches".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("square in".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("sq inch".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("sq inches".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("sq in".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("inch²".to_string()), Ok(NonMetric::SquareInch)); assert_eq!(parse_unit("inch²".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("inches²".to_string()), Ok(NonMetric::SquareInch)); assert_eq!(parse_unit("inches²".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("in²".to_string()), Ok(NonMetric::SquareInch)); assert_eq!(parse_unit("in²".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("\"²".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("″²".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("inch^2".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("inches^2".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("in^2".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("\"^2".to_string()), Ok(NonMetric::SquareInch));
assert_eq!(parse_unit("square foot".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("square feet".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("square ft".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("sq foot".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("sq feet".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("sq ft".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("foot²".to_string()), Ok(NonMetric::SquareFoot)); assert_eq!(parse_unit("foot²".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("feet²".to_string()), Ok(NonMetric::SquareFoot)); assert_eq!(parse_unit("feet²".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("ft²".to_string()), Ok(NonMetric::SquareFoot)); assert_eq!(parse_unit("ft²".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("′²".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("foot^2".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("feet^2".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("ft^2".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("'^2".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("sf".to_string()), Ok(NonMetric::SquareFoot));
assert_eq!(parse_unit("acre".to_string()), Ok(NonMetric::Acre)); assert_eq!(parse_unit("acre".to_string()), Ok(NonMetric::Acre));
assert_eq!(parse_unit("acres".to_string()), Ok(NonMetric::Acre)); assert_eq!(parse_unit("acres".to_string()), Ok(NonMetric::Acre));
assert_eq!(parse_unit("ac".to_string()), Ok(NonMetric::Acre)); assert_eq!(parse_unit("ac".to_string()), Ok(NonMetric::Acre));
assert_eq!(parse_unit("square mile".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("square miles".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("square mi".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("sq mile".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("sq miles".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("sq mi".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("mile²".to_string()), Ok(NonMetric::SquareMile)); assert_eq!(parse_unit("mile²".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("miles²".to_string()), Ok(NonMetric::SquareMile)); assert_eq!(parse_unit("miles²".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("mi²".to_string()), Ok(NonMetric::SquareMile)); assert_eq!(parse_unit("mi²".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("mile^2".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("miles^2".to_string()), Ok(NonMetric::SquareMile));
assert_eq!(parse_unit("mi^2".to_string()), Ok(NonMetric::SquareMile));
// Unknown unit // Unknown unit
assert_eq!(parse_unit("hutenosa".to_string()), Err(ParseError::UnknownUnit("hutenosa".to_string()))); assert_eq!(parse_unit("hutenosa".to_string()), Err(ParseError::UnknownUnit("hutenosa".to_string())));
@ -304,13 +386,6 @@ mod test {
Token::Unit("ft".to_string()), Token::Unit("ft".to_string()),
] ]
); );
assert_eq!(
tokenize("ft in"),
vec![
Token::Unit("ft".to_string()),
Token::Unit("in".to_string()),
]
);
assert_eq!( assert_eq!(
tokenize("5 ft 7 in"), tokenize("5 ft 7 in"),
vec![ vec![
@ -336,5 +411,44 @@ mod test {
Token::Unit("lbs".to_string()), Token::Unit("lbs".to_string()),
] ]
); );
assert_eq!(
tokenize("sq ft"),
vec![
Token::Unit("sq ft".to_string()),
]
);
assert_eq!(
tokenize("sq ft2"),
vec![
Token::Unit("sq ft".to_string()),
Token::Number("2".to_string()),
]
);
assert_eq!(
tokenize("ft^2"),
vec![
Token::Unit("ft^2".to_string()),
]
);
assert_eq!(
tokenize("ft^22"),
vec![
Token::Unit("ft^22".to_string()),
]
);
assert_eq!(
tokenize("ft^2 2"),
vec![
Token::Unit("ft^2".to_string()),
Token::Number("2".to_string()),
]
);
assert_eq!(
tokenize("ft^2 s^-1 lb 2"),
vec![
Token::Unit("ft^2 s^-1 lb".to_string()),
Token::Number("2".to_string()),
]
);
} }
} }