我正在尝试使用Java RegEx匹配句子中的名称。仅当名称被普通文本而不是其他名称包围时,才应匹配名称。例如,我想在下面的句子中匹配 Obama 这个词:
Americans said that Obama is ...
但不是以下一个:
Americans said that Barack Obama is ...
要检查令牌是否是名称,我需要使用简单的(简单的正则表达式),而不依赖于更复杂的工具(即NER)。正则表达式使用非固定宽度量词(*):
[A-Z][a-z]*
我可以很容易地找到一种避免匹配名称的方法,其次是其他名称与否定前瞻,因为我不能在负面的后视中使用相同的正则表达式,因为存在未固定的宽度量词
换句话说,我不能使用以下正则表达式:
(?<![A-Z][a-z]*\s)Obama(?!\s[A-Z][a-z]*)
你有什么其他简单但有效的想法来解决这个问题吗?
答案 0 :(得分:1)
Java正则表达式引擎确实不支持无限宽度的后视模式,但是,Java lookbehind模式是约束宽度,这意味着,我们可以使用{{1在其中限制量词(设置最小值和最大值)。
所以,你可以使用
{n,m}
请参阅Java online demo。
由于这假设前面的单词可以是1到101个字母长,这不是最好的方法,但可能会变得足够。
此外,您可以依赖捕获:
String str = "Americans said that Obama is ... Americans said that Barack Obama is ...";
Pattern ptrn = Pattern.compile("(?<!\\b[A-Z][a-z]{0,100}\\s)Obama(?!\\s+[A-Z][a-z]*)");
Matcher matcher = ptrn.matcher(str);
while (matcher.find()) {
System.out.println(matcher.group(0));
}
请参阅another demo,Pattern ptrn = Pattern.compile("(^|\\s[a-z]+\\s+)(Obama)(?!\\s+[A-Z][a-z]*)");
// ...
while (matcher.find()) {
System.out.println(matcher.group(2));
}
将出现在第2组,第1组将匹配并使用Obama
- 字符串的开头,或者空格+一个或多个小写ASCII字母和1 +空格。