Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 0 additions & 27 deletions examples/probe.rs

This file was deleted.

16 changes: 16 additions & 0 deletions src/tn/en/electronic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ lazy_static! {
/// Product acronyms upper-cased in email/URL context.
static ref BRAND: HashSet<&'static str> =
["nvidia", "cuda", "dgx", "rtx", "basepod"].into_iter().collect();

/// File-extension acronyms upper-cased when they are the final ".ext".
static ref EXT_UPPER: HashSet<&'static str> =
["html", "htm", "xml", "css", "json", "php", "asp", "sql"].into_iter().collect();
}

/// Parse an email or URL to spoken form.
Expand Down Expand Up @@ -221,6 +225,18 @@ fn render_remainder(s: &str, context: bool) -> String {
}
}
flush(&mut buf, &mut out);

// Upper-case a known acronym file extension in the final ".ext" label
// ("intro.html" → "… dot HTML"), leaving an identically-named directory
// ("…/html/…") lower case.
let n = out.len();
if n >= 2 && out[n - 2] == "dot" {
let lower = out[n - 1].to_ascii_lowercase();
if EXT_UPPER.contains(lower.as_str()) {
out[n - 1] = lower.to_ascii_uppercase();
}
}

out.join(" ")
}

Expand Down
13 changes: 13 additions & 0 deletions src/tn/en/measure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,12 @@ pub fn parse(input: &str) -> Option<String> {
continue;
}

// A spaced 4-digit decade ("1980 s") is not "1980 seconds" — leave it
// to the date tagger, which reads it as "nineteen eighties".
if unit_str == "s" && is_spaced_decade(num_part) {
continue;
}

// Scale word between the number and unit ("100 million kg").
if let Some(scaled) = parse_scaled(num_part) {
return Some(format!("{} {}", scaled, unit_info.plural));
Expand Down Expand Up @@ -213,6 +219,13 @@ pub fn parse(input: &str) -> Option<String> {
parse_per(trimmed)
}

/// A 4-digit multiple of ten ("1980") — a decade written before a spaced "s".
fn is_spaced_decade(num: &str) -> bool {
num.len() == 4
&& num.chars().all(|c| c.is_ascii_digit())
&& num.parse::<u32>().map(|n| n % 10 == 0).unwrap_or(false)
}

/// Read a "value/unit" form where the right side is a bare unit.
fn parse_per(input: &str) -> Option<String> {
let (left, right) = input.split_once('/')?;
Expand Down
15 changes: 15 additions & 0 deletions src/tn/en/serial.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,21 @@ pub fn parse(input: &str) -> Option<String> {
return None;
}

// Rate notation: "<digits>/<single letter>" → "<cardinal> per <LETTER>".
if let Some((num, unit)) = token.split_once('/') {
if !num.is_empty()
&& num.chars().all(|c| c.is_ascii_digit())
&& unit.len() == 1
&& unit.chars().all(|c| c.is_ascii_alphabetic())
{
return Some(format!(
"{} per {}",
number_to_words(num.parse().ok()?),
unit.to_ascii_uppercase()
));
}
}

let mut out = String::new();
let mut chars = token.chars().peekable();
while let Some(&c) = chars.peek() {
Expand Down
6 changes: 3 additions & 3 deletions tests/parity_baseline.tsv
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ en itn word 55 55
en itn word_cased 49 49
en tn address 8 11
en tn cardinal 18 18
en tn date 52 54
en tn date 53 54
en tn decimal 12 12
en tn electronic 40 45
en tn electronic 41 45
en tn fraction 16 16
en tn math 4 4
en tn measure 11 21
Expand All @@ -62,7 +62,7 @@ en tn punctuation 39 63
en tn punctuation_match_input 4 13
en tn range 19 20
en tn roman 4 4
en tn serial 27 32
en tn serial 28 32
en tn special_text 9 10
en tn telephone 20 20
en tn time 21 21
Expand Down
Loading