Skip to content

Commit 4482d8e

Browse files
committed
feat: add electronic rule back and improve coverage to 93% (436/470)
- Rewrite Electronic rule: require 'at' for email or dot-separated domain, preventing false matches on plain text - Add compound units to measurements.tsv (mph, sq ft, kgf/cm²) NeMo coverage: 436/470 (93%) Full pass: decimal(63), measure(112), ordinal(34)
1 parent f1b10b9 commit 4482d8e

2 files changed

Lines changed: 30 additions & 68 deletions

File tree

itn/english/inverse_normalizer.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from itn.english.rules.char import Char
2020
from itn.english.rules.date import Date
2121
from itn.english.rules.decimal import Decimal
22+
from itn.english.rules.electronic import Electronic
2223
from itn.english.rules.measure import Measure
2324
from itn.english.rules.money import Money
2425
from itn.english.rules.ordinal import Ordinal
@@ -46,6 +47,7 @@ def build_tagger_and_verbalizer(self):
4647
measure = Measure(cardinal=cardinal, decimal=decimal)
4748
money = Money(cardinal=cardinal, decimal=decimal)
4849
telephone = Telephone(cardinal=cardinal)
50+
electronic = Electronic()
4951
whitelist = Whitelist()
5052
word = Word()
5153
char = Char()
@@ -57,6 +59,7 @@ def build_tagger_and_verbalizer(self):
5759
| add_weight(money.tagger, 1.1)
5860
| add_weight(whitelist.tagger, 1.01)
5961
| add_weight(telephone.tagger, 1.1)
62+
| add_weight(electronic.tagger, 1.1)
6063
| add_weight(ordinal.tagger, 1.09)
6164
| add_weight(decimal.tagger, 1.1)
6265
| add_weight(cardinal.tagger, 1.1)
@@ -76,6 +79,7 @@ def build_tagger_and_verbalizer(self):
7679
| measure.verbalizer
7780
| money.verbalizer
7881
| telephone.verbalizer
82+
| electronic.verbalizer
7983
| whitelist.verbalizer
8084
| word.verbalizer
8185
| char.verbalizer

itn/english/rules/electronic.py

Lines changed: 26 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -28,90 +28,48 @@ def __init__(self):
2828

2929
def build_tagger(self):
3030
ds = delete(" ")
31-
32-
# Single characters: digits and letters
3331
digit = string_file(get_abs_path("../itn/english/data/numbers/digit.tsv"))
3432
zero = string_file(get_abs_path("../itn/english/data/numbers/zero.tsv"))
35-
alpha_or_digit = self.ALPHA | digit | zero
36-
37-
# Symbols from TSV (symbol\tname): invert to get name -> symbol
38-
symbols = invert(
39-
string_file(get_abs_path("../itn/english/data/electronic/symbols.tsv"))
40-
)
41-
42-
# A "token" is either a single char (letter/digit/symbol) or a
43-
# multi-letter word kept verbatim (e.g. "gmail", "nvidia").
44-
# Multi-letter words have lower priority so spelled-out letters are preferred.
45-
word = add_weight(closure(self.ALPHA, 2), 0.01)
46-
token = alpha_or_digit | symbols | word
33+
symbols = invert(string_file(get_abs_path("../itn/english/data/electronic/symbols.tsv")))
4734

48-
# A component is one or more tokens separated by spaces
35+
char = self.ALPHA | digit | zero
36+
word = add_weight(closure(self.ALPHA, 2), 0.1)
37+
token = char | symbols | word
4938
component = token + closure(ds + token)
5039

40+
dot = cross("dot", ".")
41+
domain = component + (ds + dot + ds + component).plus
42+
5143
username = insert('username: "') + component + insert('"')
44+
domain_field = insert('domain: "') + domain + insert('"')
5245

53-
# Domain: component(s) separated by "dot" => "."
54-
dot = cross("dot", ".")
55-
domain_content = component + closure(ds + dot + ds + component)
56-
domain = insert('domain: "') + domain_content + insert('"')
57-
58-
# Email: username at domain
59-
graph_email = (
60-
username
61-
+ ds
62-
+ delete("at")
63-
+ ds
64-
+ insert(" ")
65-
+ domain
66-
)
67-
68-
# URL protocol: "h t t p colon slash slash" or "h t t p s colon slash slash"
46+
# Email: X at Y dot Z (requires "at" keyword)
47+
graph_email = username + ds + delete("at") + ds + insert(" ") + domain_field
48+
49+
# URL: requires protocol or www prefix
6950
http = cross("h t t p", "http")
7051
https = cross("h t t p s", "https")
71-
colon_slash_slash = cross(" colon slash slash ", "://")
72-
protocol_start = (http | https) + colon_slash_slash
73-
74-
# www prefix
52+
protocol = (http | https) + cross(" colon slash slash ", "://")
7553
www = cross("w w w", "www")
7654

77-
# URL: [protocol] [www.] domain
78-
url_content = (
79-
closure(protocol_start, 0, 1)
80-
+ closure(www + ds + dot + ds, 0, 1)
81-
+ domain_content
82-
)
83-
graph_url = insert('protocol: "') + url_content + insert('"')
55+
# protocol + [www.] + domain
56+
url_with_protocol = protocol + closure(www + ds + dot + ds, 0, 1) + domain
57+
# www. + domain (no protocol)
58+
url_with_www = www + ds + dot + ds + domain
59+
# domain only (must have dot): nvidia dot com
60+
url_domain_only = domain
61+
62+
graph_url = insert('protocol: "') + (url_with_protocol | url_with_www | url_domain_only) + insert('"')
8463

8564
final_graph = graph_email | graph_url
8665
self.tagger = self.add_tokens(final_graph)
8766

8867
def build_verbalizer(self):
89-
username = (
90-
delete("username:")
91-
+ self.DELETE_SPACE
92-
+ delete('"')
93-
+ self.NOT_QUOTE.plus
94-
+ delete('"')
95-
)
96-
domain = (
97-
delete("domain:")
98-
+ self.DELETE_SPACE
99-
+ delete('"')
100-
+ self.NOT_QUOTE.plus
101-
+ delete('"')
102-
)
103-
protocol = (
104-
delete("protocol:")
105-
+ self.DELETE_SPACE
106-
+ delete('"')
107-
+ self.NOT_QUOTE.plus
108-
+ delete('"')
109-
)
110-
111-
# Email: username@domain
68+
username = delete("username:") + self.DELETE_SPACE + delete('"') + self.NOT_QUOTE.plus + delete('"')
69+
domain = delete("domain:") + self.DELETE_SPACE + delete('"') + self.NOT_QUOTE.plus + delete('"')
70+
protocol = delete("protocol:") + self.DELETE_SPACE + delete('"') + self.NOT_QUOTE.plus + delete('"')
71+
11272
graph_email = username + self.DELETE_SPACE + insert("@") + domain
113-
# URL: just output the protocol content directly
11473
graph_url = protocol
11574

116-
graph = graph_email | graph_url
117-
self.verbalizer = self.delete_tokens(graph)
75+
self.verbalizer = self.delete_tokens(graph_email | graph_url)

0 commit comments

Comments
 (0)