有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

不固定长度的java正则表达式Lookbehind

我试图用Java正则表达式匹配句子中的一个名字。仅当名称由普通文本而非其他名称包围时,才应匹配该名称。例如,我想在下面的句子中匹配单词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]*)

你还有其他简单但有效的方法来解决这个问题吗


共 (1) 个答案

  1. # 1 楼答案

    的确,Java正则表达式引擎不支持无限宽度查找模式,但是,Java查找模式是受限宽度,这意味着我们可以在其内部使用{n,m}限制量词(设置了最小值和最大值)

    所以,你可以使用

    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));
    }
    

    Java online demo

    因为这假设单词的长度可以是1到101个字母,所以这不是最好的方法,但可能已经足够了

    此外,您还可以依靠捕获:

    Pattern ptrn = Pattern.compile("(^|\\s[a-z]+\\s+)(Obama)(?!\\s+[A-Z][a-z]*)");
    // ...
    while (matcher.find()) {
        System.out.println(matcher.group(2));
    }
    

    请参见another demoObama将出现在组2中,组1将匹配并使用(^|\\s[a-z]+\\s+)-字符串开头,或一个空格+一个或多个小写ASCII字母和1+空格