我正在为包含普通文本、编程代码和其他非语言片段的文档编制索引。出于不太相关的原因,我试图将内容标记为普通语言的小写字符串和单字符符号。
因此输入
a few words. Cost*count
应该生成令牌
[a] [few] [words] [.] [cost] [*] [count]
到目前为止非常简单。但我想处理";化合物";单词,因为内容可以包括orderdate、面向对象和class.method等单词。
我遵循的原则是,如果[-]、[_]和[.]中的任何一个位于两个单词字符之间,则应将其视为复合单词连接符,而不是符号;如果它们与空格、另一个符号字符或字符串的开头或结尾相邻,则应视为单独的符号字符。我可以用PatternToken处理所有这些,比如:
public static final String tokenRgx = "(([A-Za-z0-9]+[-_.])*[A-Za-z0-9]+)|[^A-Za-z0-9\s]{1}";
protected TokenStreamComponents createComponents(String fieldName) {
PatternTokenizer src = new PatternTokenizer(Pattern.compile(tokenRgx), 0);
TokenStream result = new LowerCaseFilter(src);
return new TokenStreamComponents(src, result);
}
这成功地区分了句子结尾的句号和复合词中的句号,引入负数的连字符和连字符的单词等。因此,在上述分析器中,输入:
a few words. class.simple_method_name. dd-mm-yyyy.
生成令牌
[a] [few] [words] [.] [class.simple_method_name] [.] [dd-mm-yyyy] [.]
我们快到了,但还不完全到。最后,我想把复合词分成几个部分,在每个部分保留尾随的连字符/下划线/停止字符。所以我想我需要在我的分析器中引入另一个过滤步骤,这样我最终得到的令牌集就是:
[a] [few] [words] [.] [class.] [simple_] [method_] [name] [.] [dd-] [mm-] [yyyy] [.]
这就是我遇到麻烦的部分。我认为这里需要某种PatternCaptureGroupTokenFilter,但我还没能找到正确的表达式集来获得我想要从分析器中出现的确切令牌。
我知道这一定是可能的,但我似乎走进了一堵挡住我的正则表达式墙。如果有人能给我一个启示,我需要一点洞察力或暗示。
谢谢,T
编辑:感谢@rici为我介绍解决方案
有效的字符串(包括对十进制数字的支持(是:
String tokenRegex = "-?[0-9]+\.[0-9]+|[A-Za-z0-9]+([-_.](?=[A-Za-z0-9]))?|[^A-Za-z0-9\s]";
在我看来,使用类似的正则表达式在一次扫描中完成整个任务会更容易
[A-Za-z0-9]+([-_.](?=[A-Za-z0-9]))?|[^A-Za-z0-9\s]
它使用零宽度正向断言,以便仅在前一个单词后面紧跟字母或数字时将[-._]
添加到前一个词。(因为(?=…)
是一个断言,所以它在匹配中不包括以下字符。(
在我看来,这无法正确处理十进制数字;-3.14159
将是三个令牌而不是单个数字令牌。但这取决于你的确切需求。