WeTextProcessing 0.1.11__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/PKG-INFO +1 -1
  2. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/WeTextProcessing.egg-info/PKG-INFO +1 -1
  3. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/WeTextProcessing.egg-info/SOURCES.txt +47 -1
  4. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/cardinal.py +24 -23
  5. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/license_plate.py +4 -1
  6. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/measure.py +0 -3
  7. WeTextProcessing-0.2.0/itn/zh_itn_tagger.fst +0 -0
  8. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/cardinal.py +5 -2
  9. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/math.py +14 -5
  10. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/measure.py +1 -4
  11. WeTextProcessing-0.2.0/tn/english/__init__.py +0 -0
  12. WeTextProcessing-0.2.0/tn/english/data/__init__.py +0 -0
  13. WeTextProcessing-0.2.0/tn/english/data/address/__init__.py +13 -0
  14. WeTextProcessing-0.2.0/tn/english/data/date/__init__.py +0 -0
  15. WeTextProcessing-0.2.0/tn/english/data/electronic/__init__.py +0 -0
  16. WeTextProcessing-0.2.0/tn/english/data/measure/__init__.py +13 -0
  17. WeTextProcessing-0.2.0/tn/english/data/money/__init__.py +0 -0
  18. WeTextProcessing-0.2.0/tn/english/data/number/__init__.py +13 -0
  19. WeTextProcessing-0.2.0/tn/english/data/ordinal/__init__.py +0 -0
  20. WeTextProcessing-0.2.0/tn/english/data/roman/__init__.py +0 -0
  21. WeTextProcessing-0.2.0/tn/english/data/telephone/__init__.py +0 -0
  22. WeTextProcessing-0.2.0/tn/english/data/time/__init__.py +13 -0
  23. WeTextProcessing-0.2.0/tn/english/data/whitelist/__init__.py +0 -0
  24. WeTextProcessing-0.2.0/tn/english/normalizer.py +92 -0
  25. WeTextProcessing-0.2.0/tn/english/rules/__init__.py +0 -0
  26. WeTextProcessing-0.2.0/tn/english/rules/cardinal.py +186 -0
  27. WeTextProcessing-0.2.0/tn/english/rules/date.py +319 -0
  28. WeTextProcessing-0.2.0/tn/english/rules/decimal.py +194 -0
  29. WeTextProcessing-0.2.0/tn/english/rules/electronic.py +213 -0
  30. WeTextProcessing-0.2.0/tn/english/rules/fraction.py +139 -0
  31. WeTextProcessing-0.2.0/tn/english/rules/measure.py +327 -0
  32. WeTextProcessing-0.2.0/tn/english/rules/money.py +124 -0
  33. WeTextProcessing-0.2.0/tn/english/rules/ordinal.py +96 -0
  34. WeTextProcessing-0.2.0/tn/english/rules/punctuation.py +81 -0
  35. WeTextProcessing-0.2.0/tn/english/rules/roman.py +149 -0
  36. WeTextProcessing-0.2.0/tn/english/rules/telephone.py +180 -0
  37. WeTextProcessing-0.2.0/tn/english/rules/time.py +167 -0
  38. WeTextProcessing-0.2.0/tn/english/rules/whitelist.py +153 -0
  39. WeTextProcessing-0.2.0/tn/english/rules/word.py +59 -0
  40. WeTextProcessing-0.2.0/tn/english/test/__init__.py +0 -0
  41. WeTextProcessing-0.2.0/tn/english/test/cardinal_test.py +28 -0
  42. WeTextProcessing-0.2.0/tn/english/test/date_test.py +28 -0
  43. WeTextProcessing-0.2.0/tn/english/test/decimal_test.py +28 -0
  44. WeTextProcessing-0.2.0/tn/english/test/electronic_test.py +28 -0
  45. WeTextProcessing-0.2.0/tn/english/test/fraction_test.py +28 -0
  46. WeTextProcessing-0.2.0/tn/english/test/measure_test.py +28 -0
  47. WeTextProcessing-0.2.0/tn/english/test/money_test.py +28 -0
  48. WeTextProcessing-0.2.0/tn/english/test/normalizer_test.py +28 -0
  49. WeTextProcessing-0.2.0/tn/english/test/ordinal_test.py +28 -0
  50. WeTextProcessing-0.2.0/tn/english/test/roman_test.py +28 -0
  51. WeTextProcessing-0.2.0/tn/english/test/telephone_test.py +28 -0
  52. WeTextProcessing-0.2.0/tn/english/test/time_test.py +28 -0
  53. WeTextProcessing-0.2.0/tn/english/test/utils.py +32 -0
  54. WeTextProcessing-0.2.0/tn/english/test/whitelist_test.py +28 -0
  55. WeTextProcessing-0.2.0/tn/english/test/word_test.py +28 -0
  56. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/main.py +22 -11
  57. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/processor.py +17 -1
  58. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/token_parser.py +11 -2
  59. WeTextProcessing-0.2.0/tn/utils.py +92 -0
  60. WeTextProcessing-0.2.0/tn/zh_tn_tagger.fst +0 -0
  61. WeTextProcessing-0.1.11/itn/zh_itn_tagger.fst +0 -0
  62. WeTextProcessing-0.1.11/tn/zh_tn_tagger.fst +0 -0
  63. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/LICENSE +0 -0
  64. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/README.md +0 -0
  65. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/WeTextProcessing.egg-info/dependency_links.txt +0 -0
  66. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/WeTextProcessing.egg-info/entry_points.txt +0 -0
  67. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/WeTextProcessing.egg-info/requires.txt +0 -0
  68. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/WeTextProcessing.egg-info/top_level.txt +0 -0
  69. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/__init__.py +0 -0
  70. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/__main__.py +0 -0
  71. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/__init__.py +0 -0
  72. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/inverse_normalizer.py +0 -0
  73. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/__init__.py +0 -0
  74. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/char.py +0 -0
  75. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/date.py +0 -0
  76. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/fraction.py +0 -0
  77. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/math.py +0 -0
  78. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/money.py +0 -0
  79. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/postprocessor.py +0 -0
  80. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/time.py +0 -0
  81. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/rules/whitelist.py +0 -0
  82. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/test/__init__.py +0 -0
  83. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/test/normalizer_test.py +0 -0
  84. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/chinese/test/utils.py +0 -0
  85. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/main.py +0 -0
  86. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/itn/zh_itn_verbalizer.fst +0 -0
  87. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/setup.cfg +0 -0
  88. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/setup.py +0 -0
  89. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/__init__.py +0 -0
  90. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/__main__.py +0 -0
  91. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/__init__.py +0 -0
  92. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/normalizer.py +0 -0
  93. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/__init__.py +0 -0
  94. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/char.py +0 -0
  95. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/date.py +0 -0
  96. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/fraction.py +0 -0
  97. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/money.py +0 -0
  98. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/postprocessor.py +0 -0
  99. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/preprocessor.py +0 -0
  100. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/sport.py +0 -0
  101. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/time.py +0 -0
  102. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/rules/whitelist.py +0 -0
  103. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/__init__.py +0 -0
  104. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/cardinal_test.py +0 -0
  105. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/char_test.py +0 -0
  106. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/date_test.py +0 -0
  107. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/fraction_test.py +0 -0
  108. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/math_test.py +0 -0
  109. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/measure_test.py +0 -0
  110. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/money_test.py +0 -0
  111. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/normalizer_test.py +0 -0
  112. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/postprocessor_test.py +0 -0
  113. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/preprocessor_test.py +0 -0
  114. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/sport_test.py +0 -0
  115. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/time_test.py +0 -0
  116. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/token_parser_test.py +0 -0
  117. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/utils.py +0 -0
  118. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/chinese/test/whitelist_test.py +0 -0
  119. {WeTextProcessing-0.1.11 → WeTextProcessing-0.2.0}/tn/zh_tn_verbalizer.fst +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: WeTextProcessing
3
- Version: 0.1.11
3
+ Version: 0.2.0
4
4
  Summary: WeTextProcessing, including TN & ITN
5
5
  Home-page: https://github.com/wenet-e2e/WeTextProcessing
6
6
  Author: Zhendong Peng, Xingchen Song
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: WeTextProcessing
3
- Version: 0.1.11
3
+ Version: 0.2.0
4
4
  Summary: WeTextProcessing, including TN & ITN
5
5
  Home-page: https://github.com/wenet-e2e/WeTextProcessing
6
6
  Author: Zhendong Peng, Xingchen Song
@@ -34,6 +34,7 @@ tn/__main__.py
34
34
  tn/main.py
35
35
  tn/processor.py
36
36
  tn/token_parser.py
37
+ tn/utils.py
37
38
  tn/zh_tn_tagger.fst
38
39
  tn/zh_tn_verbalizer.fst
39
40
  tn/chinese/__init__.py
@@ -66,4 +67,49 @@ tn/chinese/test/sport_test.py
66
67
  tn/chinese/test/time_test.py
67
68
  tn/chinese/test/token_parser_test.py
68
69
  tn/chinese/test/utils.py
69
- tn/chinese/test/whitelist_test.py
70
+ tn/chinese/test/whitelist_test.py
71
+ tn/english/__init__.py
72
+ tn/english/normalizer.py
73
+ tn/english/data/__init__.py
74
+ tn/english/data/address/__init__.py
75
+ tn/english/data/date/__init__.py
76
+ tn/english/data/electronic/__init__.py
77
+ tn/english/data/measure/__init__.py
78
+ tn/english/data/money/__init__.py
79
+ tn/english/data/number/__init__.py
80
+ tn/english/data/ordinal/__init__.py
81
+ tn/english/data/roman/__init__.py
82
+ tn/english/data/telephone/__init__.py
83
+ tn/english/data/time/__init__.py
84
+ tn/english/data/whitelist/__init__.py
85
+ tn/english/rules/__init__.py
86
+ tn/english/rules/cardinal.py
87
+ tn/english/rules/date.py
88
+ tn/english/rules/decimal.py
89
+ tn/english/rules/electronic.py
90
+ tn/english/rules/fraction.py
91
+ tn/english/rules/measure.py
92
+ tn/english/rules/money.py
93
+ tn/english/rules/ordinal.py
94
+ tn/english/rules/punctuation.py
95
+ tn/english/rules/roman.py
96
+ tn/english/rules/telephone.py
97
+ tn/english/rules/time.py
98
+ tn/english/rules/whitelist.py
99
+ tn/english/rules/word.py
100
+ tn/english/test/__init__.py
101
+ tn/english/test/cardinal_test.py
102
+ tn/english/test/date_test.py
103
+ tn/english/test/decimal_test.py
104
+ tn/english/test/electronic_test.py
105
+ tn/english/test/fraction_test.py
106
+ tn/english/test/measure_test.py
107
+ tn/english/test/money_test.py
108
+ tn/english/test/normalizer_test.py
109
+ tn/english/test/ordinal_test.py
110
+ tn/english/test/roman_test.py
111
+ tn/english/test/telephone_test.py
112
+ tn/english/test/time_test.py
113
+ tn/english/test/utils.py
114
+ tn/english/test/whitelist_test.py
115
+ tn/english/test/word_test.py
@@ -36,6 +36,10 @@ class Cardinal(Processor):
36
36
  def build_tagger(self):
37
37
  zero = string_file('itn/chinese/data/number/zero.tsv') # 0
38
38
  digit = string_file('itn/chinese/data/number/digit.tsv') # 1 ~ 9
39
+ special_tilde = string_file(
40
+ 'itn/chinese//data/number/special_tilde.tsv') # 七八十->70~80
41
+ special_dash = string_file(
42
+ 'itn/chinese//data/number/special_dash.tsv') # 七八十->70-80
39
43
  sign = string_file('itn/chinese/data/number/sign.tsv') # + -
40
44
  dot = string_file('itn/chinese/data/number/dot.tsv') # .
41
45
 
@@ -82,7 +86,7 @@ class Cardinal(Processor):
82
86
  ten_thousand |= (thousand | hundred) + accep("万") + delete(
83
87
  "零").ques + (thousand | hundred | tens | teen | digits).ques
84
88
 
85
- # 1. 利用基础数字所构建的包含0~9的完整数字
89
+ # 1. 利用基础数字所构建的包含0~9的标准数字
86
90
  # 个/十/百/千/万
87
91
  number = digits | teen | tens | hundred | thousand | ten_thousand
88
92
  # 兆/亿
@@ -90,25 +94,19 @@ class Cardinal(Processor):
90
94
  (number + accep('亿') + delete('零').ques).ques + number)
91
95
  # 负的xxx 1.11, 1.01
92
96
  number = sign.ques + number + (dot + digits.plus).ques
93
- # 五六万,三五千,六七百,三四十
94
- special_2number = digit + insert("0~") + digit + cross("十", "0")
95
- special_2number |= digit + insert("00~") + digit + cross("百", "00")
96
- special_2number |= digit + insert("000~") + digit + cross("千", "000")
97
- special_2number |= digit + insert("0000~") + digit + cross("万", "0000")
98
- number |= special_2number
99
- # 十七八美元 => $17~18, 四十五六岁 => 45-6岁,
100
- # 三百七八公里 => 370-80km, 三百七八十千克 => 370-80kg
101
- special_3number = cross('十', '1') + digit + insert("~1") + digit
102
- special_3number |= digit + delete('十') + digit + insert("-") + digit
103
- special_3number |= digit + delete('百') + digit + insert("0-") + digit \
104
- + (insert("0") | add_weight(cross("十", "0"), -0.1))
105
- number |= add_weight(special_3number, -100.0)
97
+ # 五六万 => 5~6万,三五千 => 3000~5000,六七百 => 600~700,三四十 => 30~40
98
+ number |= special_tilde
99
+ # 十七八 => 17-8, 四十五六 => 45-6, 三百七八十 => 370-80
100
+ _special_dash = cross('十', '1') + special_dash
101
+ _special_dash |= digit + delete('十') + special_dash
102
+ _special_dash |= digit + delete('百') + special_dash
103
+ number |= _special_dash
106
104
 
107
105
  self.number = number.optimize()
108
- self.special_2number = special_2number.optimize()
109
- self.special_3number = special_3number.optimize()
106
+ self.special_tilde = special_tilde.optimize()
107
+ self.special_dash = _special_dash.optimize()
110
108
 
111
- # 2. 利用基础数字所构建的不包含0~9的完整数字
109
+ # 2. 利用基础数字所构建的不包含0~9的标准数字
112
110
  # 十/百/千/万
113
111
  number_exclude_0_to_9 = teen | tens | hundred | thousand | ten_thousand
114
112
  # 兆/亿
@@ -123,8 +121,8 @@ class Cardinal(Processor):
123
121
  # 五六万,三五千,六七百,三四十
124
122
  # 十七八美元 => $17~18, 四十五六岁 => 45-6岁,
125
123
  # 三百七八公里 => 370-80km, 三百七八十千克 => 370-80kg
126
- number_exclude_0_to_9 |= special_2number
127
- number_exclude_0_to_9 |= add_weight(special_3number, -100.0)
124
+ number_exclude_0_to_9 |= special_tilde
125
+ number_exclude_0_to_9 |= add_weight(_special_dash, -100.0)
128
126
 
129
127
  self.number_exclude_0_to_9 = (sign.ques +
130
128
  number_exclude_0_to_9).optimize()
@@ -136,16 +134,19 @@ class Cardinal(Processor):
136
134
  cardinal |= (number + dot + digits.plus)
137
135
  # cardinal string like 110 or 12306 or 13125617878, used in phone,
138
136
  # 340621199806051223, used in ID card
137
+ idcard_last_char = digits | 'X' | 'x'
139
138
  cardinal |= (digits**3 | digits**4 | digits**5 | digits**11
140
- | digits**18)
139
+ | (digits**17 + idcard_last_char) | digits**18)
141
140
 
142
- # 4. 特殊格式的数字 + 包含或不包含0~9的完整数字
141
+ # 4. 特殊格式的数字 + 标准数字
143
142
  # cardinal string like 23
144
143
  if self.enable_standalone_number:
145
144
  if self.enable_0_to_9:
146
- cardinal |= number
145
+ # 特殊格式数字为第一优先级, 标准数字为第二优先级, 如 "一二三四"
146
+ # 优先转译为 "1234" 而非 "1~2 3~4"
147
+ cardinal |= add_weight(number, 0.1)
147
148
  else:
148
- cardinal |= number_exclude_0_to_9
149
+ cardinal |= add_weight(number_exclude_0_to_9, 0.1)
149
150
  tagger = insert('value: "') + cardinal + (insert(" ") + cardinal).star \
150
151
  + insert('"')
151
152
  self.tagger = self.add_tokens(tagger)
@@ -27,8 +27,11 @@ class LicensePlate(Processor):
27
27
 
28
28
  def build_tagger(self):
29
29
  digit = string_file('itn/chinese/data/number/digit.tsv') # 1 ~ 9
30
+ zero = string_file('itn/chinese/data/number/zero.tsv') # 0
31
+ digits = zero | digit
30
32
  province = string_file(
31
33
  'itn/chinese/data/license_plate/province.tsv') # 皖
32
- license_plate = province + self.ALPHA + (self.ALPHA | digit)**5
34
+ license_plate = province + self.ALPHA + (self.ALPHA | digits)**5
35
+ license_plate |= province + self.ALPHA + (self.ALPHA | digits)**6
33
36
  tagger = insert('value: "') + license_plate + insert('"')
34
37
  self.tagger = self.add_tokens(tagger)
@@ -31,7 +31,6 @@ class Measure(Processor):
31
31
  def build_tagger(self):
32
32
  units_en = string_file('itn/chinese/data/measure/units_en.tsv')
33
33
  units_zh = string_file('itn/chinese/data/measure/units_zh.tsv')
34
- digit = string_file('itn/chinese/data/number/digit.tsv') # 1 ~ 9
35
34
  sign = string_file('itn/chinese/data/number/sign.tsv') # + -
36
35
  to = cross('到', '~') | cross('到百分之', '~')
37
36
 
@@ -52,8 +51,6 @@ class Measure(Processor):
52
51
 
53
52
  # 十千米每小时 => 10km/h, 十一到一百千米每小时 => 11~100km/h
54
53
  measure = number + (to + number).ques + units
55
- # 七八块钱
56
- measure |= digit + insert("~") + digit + units
57
54
  tagger = insert('value: "') + (measure | percent) + insert('"')
58
55
 
59
56
  # 每小时十千米 => 10km/h, 每小时三十到三百一十一千米 => 30~311km/h
@@ -64,11 +64,13 @@ class Cardinal(Processor):
64
64
  number @= self.build_rule(
65
65
  cross('二百', '两百')
66
66
  | cross('二千', '两千')
67
- | cross('二万', '两万'))
68
- self.number = accep('约').ques + accep('人均').ques + number.optimize()
67
+ | cross('二万', '两万')).optimize()
68
+ percent = insert('百分之') + number + delete('%')
69
+ self.number = accep('约').ques + accep('人均').ques + (number | percent)
69
70
 
70
71
  # cardinal string like 127.0.0.1, used in ID, IP, etc.
71
72
  cardinal = digits.plus + (dot + digits.plus)**3
73
+ cardinal |= percent
72
74
  # xxxx-xxx-xxx
73
75
  cardinal |= digits.plus + (delete('-') + digits.plus)**2
74
76
  # xxx-xxxxxxxx
@@ -76,6 +78,7 @@ class Cardinal(Processor):
76
78
  # three or five or eleven phone numbers
77
79
  phone_digits = digits @ self.build_rule(cross('一', '幺'))
78
80
  phone = phone_digits**3 | phone_digits**5 | phone_digits**11
81
+ phone |= accep("尾号") + (accep("是") | accep("为")).ques + phone_digits**4
79
82
  cardinal |= add_weight(phone, -1.0)
80
83
 
81
84
  tagger = insert('value: "') + cardinal + insert('"')
@@ -15,23 +15,32 @@
15
15
  from tn.chinese.rules.cardinal import Cardinal
16
16
  from tn.processor import Processor
17
17
 
18
- from pynini import string_file
18
+ from pynini import cross, string_file
19
19
  from pynini.lib.pynutil import delete, insert
20
20
 
21
21
 
22
22
  class Math(Processor):
23
23
 
24
24
  def __init__(self):
25
- super().__init__(name='math')
25
+ super().__init__(name="math")
26
26
  self.build_tagger()
27
27
  self.build_verbalizer()
28
28
 
29
29
  def build_tagger(self):
30
- operator = string_file('tn/chinese/data/math/operator.tsv')
30
+ operator = string_file("tn/chinese/data/math/operator.tsv")
31
+ # When it appears alone, it is treated as punctuation
32
+ symbols = (
33
+ cross("~", "到")
34
+ | cross(":", "比")
35
+ | cross("<", "小于")
36
+ | cross(">", "大于")
37
+ )
31
38
 
32
39
  number = Cardinal().number
33
- tagger = (number + ((delete(' ').ques + operator + delete(' ').ques +
34
- number).plus).ques)
40
+ tagger = (
41
+ number
42
+ + (delete(" ").ques + (operator | symbols) + delete(" ").ques + number).star
43
+ )
35
44
  tagger |= operator
36
45
  tagger = insert('value: "') + tagger + insert('"')
37
46
  self.tagger = self.add_tokens(tagger)
@@ -35,8 +35,6 @@ class Measure(Processor):
35
35
  to = cross('-', '到') | cross('~', '到') | accep('到')
36
36
 
37
37
  number = Cardinal().number
38
- percent = insert('百分之') + number + delete('%')
39
-
40
38
  number @= self.build_rule(cross('二', '两'), '[BOS]', '[EOS]')
41
39
  # 1-11个,1个-11个
42
40
  prefix = number + (rmspace + units).ques + to
@@ -55,8 +53,7 @@ class Measure(Processor):
55
53
  prefix = cardinal + (rmspace + unit).ques + to
56
54
  annual = prefix.ques + cardinal + unit
57
55
 
58
- tagger = insert('value: "') + (measure | percent
59
- | annual) + insert('"')
56
+ tagger = insert('value: "') + (measure | annual) + insert('"')
60
57
 
61
58
  # 10km/h
62
59
  rmsign = rmspace + delete('/') + rmspace
File without changes
File without changes
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 2021, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
@@ -0,0 +1,13 @@
1
+ # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
@@ -0,0 +1,92 @@
1
+ # Copyright (c) 2022 Zhendong Peng (pzd17@tsinghua.org.cn)
2
+ # Copyright (c) 2024 Xingchen Song (sxc19@tsinghua.org.cn)
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ from tn.processor import Processor
17
+ from tn.english.rules.cardinal import Cardinal
18
+ from tn.english.rules.ordinal import Ordinal
19
+ from tn.english.rules.decimal import Decimal
20
+ from tn.english.rules.fraction import Fraction
21
+ from tn.english.rules.word import Word
22
+ from tn.english.rules.date import Date
23
+ from tn.english.rules.time import Time
24
+ from tn.english.rules.measure import Measure
25
+ from tn.english.rules.money import Money
26
+ from tn.english.rules.telephone import Telephone
27
+ from tn.english.rules.electronic import Electronic
28
+ from tn.english.rules.whitelist import WhiteList
29
+ from tn.english.rules.punctuation import Punctuation
30
+
31
+ from pynini.lib.pynutil import add_weight, delete
32
+ from importlib_resources import files
33
+
34
+
35
+ class Normalizer(Processor):
36
+
37
+ def __init__(self, cache_dir=None, overwrite_cache=False):
38
+ super().__init__(name='en_normalizer', ordertype="en_tn")
39
+ if cache_dir is None:
40
+ cache_dir = files("tn")
41
+ self.build_fst('en_tn', cache_dir, overwrite_cache)
42
+
43
+ def build_tagger(self):
44
+ cardinal = add_weight(Cardinal().tagger, 1.0)
45
+ ordinal = add_weight(Ordinal().tagger, 1.0)
46
+ decimal = add_weight(Decimal().tagger, 1.0)
47
+ fraction = add_weight(Fraction().tagger, 1.0)
48
+ date = add_weight(Date().tagger, 0.99)
49
+ time = add_weight(Time().tagger, 1.00)
50
+ measure = add_weight(Measure().tagger, 1.00)
51
+ money = add_weight(Money().tagger, 1.00)
52
+ telephone = add_weight(Telephone().tagger, 1.00)
53
+ electronic = add_weight(Electronic().tagger, 1.00)
54
+ word = add_weight(Word().tagger, 100)
55
+ whitelist = add_weight(WhiteList().tagger, 1.00)
56
+ punct = add_weight(Punctuation().tagger, 2.00)
57
+ # TODO(xcsong): add roman
58
+ tagger = punct.star + \
59
+ (cardinal | ordinal | word
60
+ | date | decimal | fraction
61
+ | time | measure | money
62
+ | telephone | electronic
63
+ | whitelist
64
+ | punct).optimize() + (punct.plus | self.DELETE_SPACE)
65
+ # delete the last space
66
+ self.tagger = tagger.star @ self.build_rule(delete(' '), r='[EOS]')
67
+
68
+ def build_verbalizer(self):
69
+ cardinal = Cardinal().verbalizer
70
+ ordinal = Ordinal().verbalizer
71
+ decimal = Decimal().verbalizer
72
+ fraction = Fraction().verbalizer
73
+ word = Word().verbalizer
74
+ date = Date().verbalizer
75
+ time = Time().verbalizer
76
+ measure = Measure().verbalizer
77
+ money = Money().verbalizer
78
+ telephone = Telephone().verbalizer
79
+ electronic = Electronic().verbalizer
80
+ whitelist = WhiteList().verbalizer
81
+ punct = Punctuation().verbalizer
82
+ verbalizer = \
83
+ (cardinal | ordinal | word
84
+ | date | decimal
85
+ | fraction | time
86
+ | measure | money
87
+ | telephone
88
+ | electronic
89
+ | whitelist
90
+ | punct).optimize() + punct.ques + self.INSERT_SPACE
91
+ self.verbalizer = verbalizer.star @ self.build_rule(delete(' '),
92
+ r='[EOS]')
File without changes
@@ -0,0 +1,186 @@
1
+ # Copyright (c) 2021, NVIDIA CORPORATION. All rights reserved.
2
+ # Copyright (c) 2024, WENET COMMUNITY. Xingchen Song (sxc19@tsinghua.org.cn).
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ import pynini
17
+ from pynini.examples import plurals
18
+ from pynini.lib import pynutil
19
+
20
+ from tn.processor import Processor
21
+ from tn.utils import get_abs_path
22
+
23
+
24
+ class Cardinal(Processor):
25
+
26
+ def __init__(self, deterministic: bool = False):
27
+ """
28
+ Args:
29
+ deterministic: if True will provide a single transduction option,
30
+ for False multiple transduction are generated (used for audio-based normalization)
31
+ """
32
+ super().__init__('cardinal', ordertype="en_tn")
33
+ self.deterministic = deterministic
34
+ self.build_tagger()
35
+ self.build_verbalizer()
36
+
37
+ def build_tagger(self):
38
+ """
39
+ Finite state transducer for classifying cardinals, e.g.
40
+ -23 -> cardinal { negative: "true" integer: "twenty three" }
41
+ """
42
+ # TODO replace to have "oh" as a default for "0"
43
+ graph = pynini.Far(
44
+ get_abs_path(
45
+ "english/data/number/cardinal_number_name.far")).get_fst()
46
+ graph_au = pynini.Far(
47
+ get_abs_path(
48
+ "english/data/number/cardinal_number_name_au.far")).get_fst()
49
+ self.graph_hundred_component_at_least_one_none_zero_digit = (
50
+ pynini.closure(self.DIGIT, 2, 3)
51
+ | pynini.difference(self.DIGIT, pynini.accep("0"))) @ graph
52
+
53
+ graph_digit = pynini.string_file(
54
+ get_abs_path("english/data/number/digit.tsv"))
55
+ graph_zero = pynini.string_file(
56
+ get_abs_path("english/data/number/zero.tsv"))
57
+
58
+ single_digits_graph = pynini.invert(graph_digit | graph_zero)
59
+ self.single_digits_graph = single_digits_graph + pynini.closure(
60
+ self.INSERT_SPACE + single_digits_graph)
61
+
62
+ if not self.deterministic:
63
+ # for a single token allow only the same normalization
64
+ # "007" -> {"oh oh seven", "zero zero seven"} not {"oh zero seven"}
65
+ single_digits_graph_zero = pynini.invert(graph_digit | graph_zero)
66
+ single_digits_graph_oh = pynini.invert(graph_digit) | pynini.cross(
67
+ "0", "oh")
68
+
69
+ self.single_digits_graph = single_digits_graph_zero + pynini.closure(
70
+ self.INSERT_SPACE + single_digits_graph_zero)
71
+ self.single_digits_graph |= single_digits_graph_oh + pynini.closure(
72
+ self.INSERT_SPACE + single_digits_graph_oh)
73
+
74
+ single_digits_graph_with_commas = pynini.closure(
75
+ self.single_digits_graph + self.INSERT_SPACE, 1,
76
+ 3) + pynini.closure(
77
+ pynutil.delete(",") + single_digits_graph +
78
+ self.INSERT_SPACE + single_digits_graph +
79
+ self.INSERT_SPACE + single_digits_graph, 1)
80
+
81
+ graph = (pynini.closure(self.DIGIT, 1, 3) +
82
+ (pynini.closure(pynutil.delete(",") + self.DIGIT**3)
83
+ | pynini.closure(self.DIGIT**3))) @ graph
84
+
85
+ self.graph = graph
86
+ self.graph_with_and = self.add_optional_and(graph)
87
+
88
+ if self.deterministic:
89
+ long_numbers = pynini.compose(self.DIGIT**(5, ...),
90
+ self.single_digits_graph).optimize()
91
+ self.long_numbers = plurals._priority_union(
92
+ long_numbers, self.graph_with_and,
93
+ pynini.closure(self.VCHAR)).optimize()
94
+ cardinal_with_leading_zeros = pynini.compose(
95
+ pynini.accep("0") + pynini.closure(self.DIGIT),
96
+ self.single_digits_graph)
97
+ final_graph = self.long_numbers | cardinal_with_leading_zeros
98
+ final_graph |= self.add_optional_and(graph_au)
99
+ else:
100
+ leading_zeros = pynini.compose(
101
+ pynini.closure(pynini.accep("0"), 1), self.single_digits_graph)
102
+ cardinal_with_leading_zeros = (
103
+ leading_zeros + self.INSERT_SPACE + pynini.compose(
104
+ pynini.closure(self.DIGIT), self.graph_with_and))
105
+ self.long_numbers = self.graph_with_and | pynutil.add_weight(
106
+ self.single_digits_graph, 0.0001)
107
+ # add small weight to non-default graphs to make sure the deterministic option is listed first
108
+ final_graph = (self.long_numbers
109
+ | pynutil.add_weight(
110
+ single_digits_graph_with_commas, 0.0001)
111
+ | cardinal_with_leading_zeros).optimize()
112
+
113
+ one_to_a_replacement_graph = (
114
+ pynini.cross("one hundred", "a hundred")
115
+ | pynini.cross("one thousand", "thousand")
116
+ | pynini.cross("one million", "a million"))
117
+ final_graph |= pynini.compose(
118
+ final_graph,
119
+ one_to_a_replacement_graph.optimize() +
120
+ pynini.closure(self.VCHAR)).optimize()
121
+ # remove commas for 4 digits numbers
122
+ four_digit_comma_graph = (
123
+ self.DIGIT - "0") + pynutil.delete(",") + self.DIGIT**3
124
+ final_graph |= pynini.compose(four_digit_comma_graph.optimize(),
125
+ final_graph).optimize()
126
+
127
+ self.final_graph = final_graph
128
+ optional_minus_graph = pynini.closure(
129
+ pynutil.insert("negative: ") + pynini.cross("-", "\"true\" "), 0,
130
+ 1)
131
+ final_graph = optional_minus_graph + pynutil.insert(
132
+ "integer: \"") + final_graph + pynutil.insert("\"")
133
+ final_graph = self.add_tokens(final_graph)
134
+ self.tagger = final_graph.optimize()
135
+
136
+ def add_optional_and(self, graph):
137
+ graph_with_and = graph
138
+
139
+ graph_with_and = pynutil.add_weight(graph, 0.00001)
140
+ not_quote = pynini.closure(self.NOT_QUOTE)
141
+ no_thousand_million = pynini.difference(
142
+ not_quote, not_quote + pynini.union("thousand", "million") +
143
+ not_quote).optimize()
144
+ integer = (not_quote + pynutil.add_weight(
145
+ pynini.cross("hundred ", "hundred and ") + no_thousand_million,
146
+ -0.0001)).optimize()
147
+
148
+ no_hundred = pynini.difference(
149
+ pynini.closure(self.VCHAR),
150
+ not_quote + pynini.accep("hundred") + not_quote).optimize()
151
+ integer |= (not_quote + pynutil.add_weight(
152
+ pynini.cross("thousand ", "thousand and ") + no_hundred,
153
+ -0.0001)).optimize()
154
+
155
+ optional_hundred = pynini.compose((self.DIGIT - "0")**3,
156
+ graph).optimize()
157
+ optional_hundred = pynini.compose(
158
+ optional_hundred,
159
+ pynini.closure(self.VCHAR) + pynini.cross(" hundred", "") +
160
+ pynini.closure(self.VCHAR))
161
+ graph_with_and |= pynini.compose(graph, integer).optimize()
162
+ graph_with_and |= optional_hundred
163
+ return graph_with_and
164
+
165
+ def build_verbalizer(self):
166
+ """
167
+ Finite state transducer for verbalizing cardinal, e.g.
168
+ cardinal { negative: "true" integer: "23" } -> minus twenty three
169
+ """
170
+ optional_sign = pynini.cross("negative: \"true\"", "minus ")
171
+ if not self.deterministic:
172
+ optional_sign |= pynini.cross("negative: \"true\"", "negative ")
173
+ optional_sign |= pynini.cross("negative: \"true\"", "dash ")
174
+
175
+ self.optional_sign = pynini.closure(optional_sign + self.DELETE_SPACE,
176
+ 0, 1)
177
+
178
+ integer = pynini.closure(self.NOT_QUOTE)
179
+
180
+ self.integer = self.DELETE_SPACE + pynutil.delete(
181
+ "\"") + integer + pynutil.delete("\"")
182
+ integer = pynutil.delete("integer:") + self.integer
183
+
184
+ self.numbers = self.optional_sign + integer
185
+ delete_tokens = self.delete_tokens(self.numbers)
186
+ self.verbalizer = delete_tokens.optimize()