Skip to content

Commit b006900

Browse files
committed
fix: add OOV character handling to C++ runtime for Chinese TN
The C++ runtime previously relied on the pre-built .fst files to handle OOV (out-of-vocabulary) characters like Korean Hangul and Japanese Kana. When the FSTs were built without tag_oov=True (the default), these characters passed through unchanged instead of being wrapped in <oov> tags. This adds Unicode-range-based OOV detection as a post-processing step in Processor::Normalize. Characters outside the CJK Unified Ideographs, ASCII, and common punctuation ranges are wrapped in <oov> tags. The check is skipped if the output already contains <oov> tags (i.e., the FST was built with OOV support), avoiding double-wrapping. Fixes #368
1 parent 9dd4a69 commit b006900

2 files changed

Lines changed: 63 additions & 1 deletion

File tree

runtime/processor/wetext_processor.cc

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,49 @@
1515
#include "processor/wetext_processor.h"
1616

1717
#include "utils/wetext_log.h"
18+
#include "utils/wetext_string.h"
1819

1920
namespace wetext {
21+
22+
static char32_t UTF8ToCodePoint(const std::string& ch) {
23+
int len = UTF8CharLength(ch[0]);
24+
char32_t cp = 0;
25+
if (len == 1) {
26+
cp = static_cast<unsigned char>(ch[0]);
27+
} else if (len == 2) {
28+
cp = ((static_cast<unsigned char>(ch[0]) & 0x1F) << 6) |
29+
(static_cast<unsigned char>(ch[1]) & 0x3F);
30+
} else if (len == 3) {
31+
cp = ((static_cast<unsigned char>(ch[0]) & 0x0F) << 12) |
32+
((static_cast<unsigned char>(ch[1]) & 0x3F) << 6) |
33+
(static_cast<unsigned char>(ch[2]) & 0x3F);
34+
} else if (len == 4) {
35+
cp = ((static_cast<unsigned char>(ch[0]) & 0x07) << 18) |
36+
((static_cast<unsigned char>(ch[1]) & 0x3F) << 12) |
37+
((static_cast<unsigned char>(ch[2]) & 0x3F) << 6) |
38+
(static_cast<unsigned char>(ch[3]) & 0x3F);
39+
}
40+
return cp;
41+
}
42+
43+
static bool IsKnownChar(char32_t cp) {
44+
// ASCII printable characters (space to ~)
45+
if (cp >= 0x0020 && cp <= 0x007E) return true;
46+
// CJK Unified Ideographs
47+
if (cp >= 0x4E00 && cp <= 0x9FFF) return true;
48+
// CJK Unified Ideographs Extension A
49+
if (cp >= 0x3400 && cp <= 0x4DBF) return true;
50+
// CJK Compatibility Ideographs
51+
if (cp >= 0xF900 && cp <= 0xFAFF) return true;
52+
// CJK Symbols and Punctuation
53+
if (cp >= 0x3000 && cp <= 0x303F) return true;
54+
// General Punctuation
55+
if (cp >= 0x2000 && cp <= 0x206F) return true;
56+
// Fullwidth forms
57+
if (cp >= 0xFF00 && cp <= 0xFFEF) return true;
58+
return false;
59+
}
60+
2061
Processor::Processor(const std::string& tagger_path,
2162
const std::string& verbalizer_path) {
2263
tagger_.reset(StdVectorFst::Read(tagger_path));
@@ -76,8 +117,28 @@ std::string Processor::Verbalize(const std::string& input) {
76117
return output;
77118
}
78119

120+
std::string Processor::TagOOV(const std::string& input) {
121+
std::vector<std::string> chars;
122+
SplitUTF8StringToChars(input, &chars);
123+
std::string output;
124+
for (const auto& ch : chars) {
125+
char32_t cp = UTF8ToCodePoint(ch);
126+
if (IsKnownChar(cp)) {
127+
output += ch;
128+
} else {
129+
output += "<oov>" + ch + "</oov>";
130+
}
131+
}
132+
return output;
133+
}
134+
79135
std::string Processor::Normalize(const std::string& input) {
80-
return Verbalize(Tag(input));
136+
std::string output = Verbalize(Tag(input));
137+
if (parse_type_ == ParseType::kZH_TN &&
138+
output.find("<oov>") == std::string::npos) {
139+
output = TagOOV(output);
140+
}
141+
return output;
81142
}
82143

83144
} // namespace wetext

runtime/processor/wetext_processor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class Processor {
3434
std::string Tag(const std::string& input);
3535
std::string Verbalize(const std::string& input);
3636
std::string Normalize(const std::string& input);
37+
std::string TagOOV(const std::string& input);
3738

3839
private:
3940
std::string ShortestPath(const StdVectorFst& lattice);

0 commit comments

Comments
 (0)