2

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

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

  • “Calvin Klein 卡尔文.克莱” - 成功拆分为“Calvin Klein”和“卡尔文.克莱”,并被标记为具有预期脚本(拉丁文和汉文)

  • “圣威廉SAINT WILLIAM” - 错误地拆分为“圣威廉SAINT”(标记为汉字)和“WILLIAM”(标记为拉丁文)。

  • “史努比SNOOPY”——被误认为是单汉代币。

我认为我的规则非常明确,但结果似乎表明并非如此。这是我的规则集:

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 会感到困惑。从正则表达式中删除那些使它一切正常。

供参考:http: //jflex.de/manual.html#SECTION000101000000000000000

4

1 回答 1

1

我询问了 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 位 wchars 转换为 UTF16/8 编码时,我发现它很有用:http ://www.fileformat.info 。例如http://www.fileformat.info/info/unicode/char/2fa1d/index.htm并向下滚动到“UTF-16(十六进制)”或“C/C++/Java 源代码”。

于 2014-02-18T19:17:11.470 回答