Tokenize 行为不端的JFlex规则-匹配的规则错误
我正在编写一个(简单?)JFlex标记器,其目标是提取一个字符串,并将中文(或者更确切地说是使用汉文)的块和拉丁语的部分分开。标记器应用于品牌名称,在我的用例中,品牌名称可能同时包含拉丁和中文名称,例如“Lenovo”联想". 品牌名称还可以包含数字(7up)、连字符(Hewlett-Packard)、符号(p&G)等。我的标记器主要起作用,但中文和非中文名称写在一起时没有空格或分隔的情况除外。具体来说,以下是成功和不成功解析的示例:Tokenize 行为不端的JFlex规则-匹配的规则错误,tokenize,stringtokenizer,jflex,chinese-locale,Tokenize,Stringtokenizer,Jflex,Chinese Locale,我正在编写一个(简单?)JFlex标记器,其目标是提取一个字符串,并将中文(或者更确切地说是使用汉文)的块和拉丁语的部分分开。标记器应用于品牌名称,在我的用例中,品牌名称可能同时包含拉丁和中文名称,例如“Lenovo”联想". 品牌名称还可以包含数字(7up)、连字符(Hewlett-Packard)、符号(p&G)等。我的标记器主要起作用,但中文和非中文名称写在一起时没有空格或分隔的情况除外。具体来说,以下是成功和不成功解析的示例: “卡尔文·克莱因卡尔文.克莱-成功拆分为“Calvin K
- “卡尔文·克莱因卡尔文.克莱-成功拆分为“Calvin Klein”和卡尔文.克莱,它们会被标记为具有预期的脚本(拉丁语和汉语)
- "圣威廉圣威廉”-被错误地分割成圣威廉“圣人”(标记为汉查尔)和“威廉”(标记为拉丁语)
- "史努比史努比”-被错误地认为是一个汉族标记
digit = [0-9]
whitespace = [ \t\r\n] | \r\n
latin = [\u0041-\u005a\u0061-\u007a\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u01bf\u01c4-\u024f]
han = [\u3400-\u9fff\uf900-\ufaff\u2f800-\u2fa1f]
// Punctuation in the middle or end of string sequences in a particular script
latin_middle = [&.\-'`‘]
latin_end = [.]
han_middle = [.]
// A basic Latin token contains a mixture of Latin characters and possibly digits.
basic_latin_tok = ({latin} | {digit})+
compound_latin_tok = {basic_latin_tok} (({whitespace}+ | {latin_middle}) {basic_latin_tok})*{latin_end}?
basic_han_tok = {han}({han} | {digit})*
| ({han} | {digit})*{han}
compound_han_tok = {basic_han_tok}({han_middle}{basic_han_tok})*
%%
{compound_latin_tok} { return "Latin"; }
{compound_han_tok} { return "Han"; }
. { /* skip everything else */ }
我做错了什么
谢谢
编辑
我问了SourceForge JFlex邮件列表上的人,其中一人回答我——结果是JFlex 1.4.*无法处理16位中无法表示的Unicode字符。由于我在上面为汉字指定的一些字符范围超过了16位值,JFlex会感到困惑。从正则表达式中删除这些字符会让一切都变得简单很好
供参考:
我问了SourceForge JFlex邮件列表上的人,其中一人回答我-
结果是JFlex 1.4.*无法处理16位中无法表示的Unicode字符
哦,但它能处理这些
首先,让我更正一下\u2f800-\u2fa1f。最后一个值确实不能在16位上表示,但这只是因为UNICODE块定义在\u2fa1d处停止,因此该值即使在其32位表示上也是UNICODE无效的
现在,说服JFlex处理问题[\u2f800-\u2fa1d]范围的诀窍是:
Java代码(和字符串文字)使用某种UTF16编码,因此16位“代理”(较高的UTF16字)后跟其他16位成对字符
对于所需的范围,您很幸运:第一个16位代理在整个范围内保持不变,即.\uD87E,而较低的16位在[\uDC00-\uDE1D]范围内变化。
因此,您的han宏变为
han = [\u3400-\u9fff\uf900-\ufaff] | \uD87E[\uDC00-\uDE1D]
在我懒得将32位WCHAR转换为UTF16/8编码时,我发现这是一个有用的资源:。例如,向下滚动到“UTF-16(十六进制)”或“C/C++/Java源代码”