1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15- from pynini import closure , cross , string_file
16- from pynini .lib .pynutil import delete , insert
15+ from pynini import closure , cross , string_file , union
16+ from pynini .lib .pynutil import add_weight , delete , insert
1717
1818from itn .english .rules .cardinal import Cardinal
1919from tn .processor import Processor
@@ -30,42 +30,70 @@ def __init__(self, cardinal=None):
3030
3131 def build_tagger (self ):
3232 ds = delete (" " )
33-
34- # Single digit: spoken word -> digit character
3533 digit = string_file (get_abs_path ("../itn/english/data/numbers/digit.tsv" ))
3634 zero = string_file (get_abs_path ("../itn/english/data/numbers/zero.tsv" ))
37- single_digit = digit | zero | cross ("o" , "0" ) | cross ("oh" , "0" )
38-
39- # 10 digits formatted as XXX-XXX-XXXX
40- ten_digits = (
41- single_digit + ds + single_digit + ds + single_digit
42- + insert ( "-" )
43- + ds + single_digit + ds + single_digit + ds + single_digit
44- + insert ( "-" )
45- + ds + single_digit + ds + single_digit + ds + single_digit + ds + single_digit
46- )
35+ single = digit | zero | cross ("o" , "0" ) | cross ("oh" , "0" )
36+
37+ # "double X" => XX
38+ double = union ( * [ cross ( f"double { w } " , f" { d } { d } " )
39+ for w , d in [( "one" , "1" ),( "two" , "2" ),( "three" , "3" ),( "four" , "4" ),
40+ ( "five" , "5" ),( "six" , "6" ),( "seven" , "7" ),( "eight" , "8" ),
41+ ( "nine" , "9" ),( "zero" , "0" ),( "oh" , "0" ),( "o" , "0" )]])
42+
43+ # two-digit cardinal: twenty three => 23
44+ two_digit = self . cardinal . graph_no_exception @ ( self . DIGIT + self . DIGIT )
4745
48- # Optional country code: "plus X" or just digits before the main number
49- country_code_digits = (
50- closure (single_digit + ds , 0 , 2 ) + single_digit
46+ # a token is 1 or 2 digits
47+ token = single | double | add_weight (two_digit , 0.002 )
48+
49+ # sequence of tokens separated by spaces
50+ seq = token + closure (ds + token )
51+
52+ # phone: XXX-XXX-XXXX
53+ phone = seq @ (
54+ self .DIGIT ** 3 + insert ("-" ) + self .DIGIT ** 3 + insert ("-" ) + self .DIGIT ** 4
5155 )
56+
57+ # country code
5258 country_code = (
53- closure (cross ("plus " , "+" ), 0 , 1 ) + country_code_digits
59+ insert ('country_code: "' )
60+ + closure (cross ("plus " , "+" ), 0 , 1 )
61+ + (closure (single + ds , 0 , 2 ) + single | add_weight (two_digit , 0.002 ))
62+ + insert ('"' )
5463 )
55- optional_country_code = closure (
56- country_code + insert (" " ) + ds , 0 , 1
64+ optional_cc = closure (country_code + ds + insert (" " ), 0 , 1 )
65+
66+ graph = optional_cc + insert ('number_part: "' ) + phone + insert ('"' )
67+
68+ # SSN: XXX-XX-XXXX
69+ ssn = seq @ (
70+ self .DIGIT ** 3 + insert ("-" ) + self .DIGIT ** 2 + insert ("-" ) + self .DIGIT ** 4
5771 )
72+ graph |= insert ('number_part: "' ) + ssn + insert ('"' )
5873
59- graph = optional_country_code + ten_digits
60- final_graph = insert ('value: "' ) + graph + insert ('"' )
61- self .tagger = self .add_tokens (final_graph )
74+ # IP: X.X.X.X
75+ ip_token = single + closure (ds + single , 0 , 2 ) | add_weight (two_digit , 0.002 )
76+ ip = ip_token + (cross (" dot " , "." ) + ip_token ) ** 3
77+ graph |= insert ('number_part: "' ) + add_weight (ip , - 0.001 ) + insert ('"' )
6278
63- def build_verbalizer (self ):
64- value = (
65- delete ("value:" )
66- + self .DELETE_SPACE
67- + delete ('"' )
68- + self .NOT_QUOTE .plus
69- + delete ('"' )
79+ # credit card: XXXX XXXX XXXX XXXX or XXXX XXXXXX XXXXX
80+ cc = seq @ (
81+ self .DIGIT ** 4 + insert (" " ) + self .DIGIT ** 4
82+ + insert (" " ) + self .DIGIT ** 4 + insert (" " ) + self .DIGIT ** 4
7083 )
71- self .verbalizer = self .delete_tokens (value )
84+ graph |= insert ('number_part: "' ) + cc + insert ('"' )
85+
86+ # serial: mixed alpha+digits, at least one digit, length >= 3
87+ serial_char = single | add_weight (two_digit , 0.002 ) | self .ALPHA
88+ serial = serial_char + closure (ds + serial_char , 2 )
89+ serial = serial @ (closure (self .ALPHA | self .DIGIT ) + self .DIGIT + closure (self .ALPHA | self .DIGIT ))
90+ graph |= insert ('number_part: "' ) + add_weight (serial , 0.001 ) + insert ('"' )
91+
92+ self .tagger = self .add_tokens (graph )
93+
94+ def build_verbalizer (self ):
95+ cc = delete ('country_code: "' ) + self .NOT_QUOTE .plus + delete ('"' )
96+ num = delete (' number_part: "' ) + self .NOT_QUOTE .plus + delete ('"' )
97+ num_only = delete ('number_part: "' ) + self .NOT_QUOTE .plus + delete ('"' )
98+ graph = cc + self .DELETE_SPACE + insert (" " ) + num | num_only
99+ self .verbalizer = self .delete_tokens (graph )
0 commit comments