Tokenize 行为不端的JFlex规则-匹配的规则错误

Tokenize 行为不端的JFlex规则-匹配的规则错误,tokenize,stringtokenizer,jflex,chinese-locale,Tokenize,Stringtokenizer,Jflex,Chinese Locale,我正在编写一个(简单?)JFlex标记器,其目标是提取一个字符串,并将中文(或者更确切地说是使用汉文)的块和拉丁语的部分分开。标记器应用于品牌名称,在我的用例中,品牌名称可能同时包含拉丁和中文名称,例如“Lenovo”联想". 品牌名称还可以包含数字(7up)、连字符(Hewlett-Packard)、符号(p&G)等。我的标记器主要起作用,但中文和非中文名称写在一起时没有空格或分隔的情况除外。具体来说,以下是成功和不成功解析的示例: “卡尔文·克莱因卡尔文.克莱-成功拆分为“Calvin K

我正在编写一个(简单?)JFlex标记器,其目标是提取一个字符串,并将中文(或者更确切地说是使用汉文)的块和拉丁语的部分分开。标记器应用于品牌名称,在我的用例中,品牌名称可能同时包含拉丁和中文名称,例如“Lenovo”联想".

品牌名称还可以包含数字(7up)、连字符(Hewlett-Packard)、符号(p&G)等。我的标记器主要起作用,但中文和非中文名称写在一起时没有空格或分隔的情况除外。具体来说,以下是成功和不成功解析的示例:

  • “卡尔文·克莱因卡尔文.克莱-成功拆分为“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源代码”