负先行正则表达式在 Java 中不起作用
Negative lookahead regex not working in Java
以下正则表达式在测试 here 时成功运行,但是当我尝试将其实现到我的 Java 代码中时,它不会 return 匹配。它使用否定前瞻来确保 MAIN LEVEL
和 Bedrooms
之间不会出现换行符。为什么它在 Java 中不起作用?
正则表达式
^\s*\bMAIN LEVEL\b\n(?:(?!\n\n)[\s\S])*\bBedrooms:\s*(.*)
Java
pattern = Pattern.compile("^\s*\bMAIN LEVEL\b\n(?:(?!\n\n)[\s\S])*\bBedrooms:\s*(.*)");
match = pattern.matcher(content);
if(match.find())
{
//Doesn't reach here
String bed = match.group(1);
bed = bed.trim();
}
content
只是从文本文件中读取的字符串,其中包含上面链接的演示中显示的确切文本。
File file = new File("C:\Users\ME\Desktop\content.txt");
content = new Scanner(file).useDelimiter("\Z").next();
更新:
我更改了我的代码以包含多行修饰符 (?m)
,但它打印出 "null".
pattern = Pattern.compile("(?m)^\s*\bMAIN LEVEL\b\n(?:(?!\n\n)[\s\S])*\bBedrooms:\s*(.*)");
match = pattern.matcher(content);
if(match.find())
{ // Still not reaching here
mainBeds=match.group(1);
mainBeds= mainBeds.trim();
}
System.out.println(mainBeds); // Prints null
这是行分隔符。您正在寻找 \n
,但您的文件实际上使用 \r\n
。如果您是 运行 Java 8,则可以将代码中的每个 \n
更改为 \R
(通用行分隔符)。对于 Java 7 或更早版本,使用 \r?\n
.
问题:
如 中所述,文件中使用的 Line-Separators
格式 (\r\n
) 与模式指定的格式 (\n
):
原码:
Pattern.compile("^\s*\bMAIN LEVEL\b
\n
(?:(?!
\n\n
)[\s\S])*\bBedrooms:\s*(.*)");
注:\r
和\n
代表什么意思,\r\n
和\n
的来龙去脉和区别,我在[=]的第二项说明80=]"side notes"节.
解决方案:
Most/all Java 版本:
您可以使用 \r?\n
来匹配两种格式,这在大多数情况下 就足够了 .
Most/all Java 版本:
可以用\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]
来匹配"Any Unicode linebreak sequence".
Java 8 及以后:
你可以使用Linebreak Matcher (\R
)。它相当于第二种方法(上面),只要有可能(Java 8 或更高版本),这是推荐的方法 .
结果代码(第三种方法):
Pattern.compile("^\s*\bMAIN LEVEL\b
\R
(?:(?!
\R\R
)[\s\S])*\bBedrooms:\s*(.*)");
旁注:
可以把\R\R
换成\R{2}
,可读性更好
存在不同格式的换行符并在不同系统中使用,因为早期操作系统从机械打字机(如打字机)继承了 "line-break logic"。
代码中的\r
表示Carriage-Return,又名CR
。这背后的想法是 return 打字光标到行的开头。
代码中的\n
表示换行,又名 LF
。这背后的想法是将打字光标移动到下一行。
最常见的换行符格式是CR-LF
(\r\n
),主要由Windows使用;和 LF
(\n
),被大多数类 UNIX 系统使用。这就是为什么 "\r?\n
在大多数情况下 足够 ",并且您可以可靠地将它用于家庭系统-等级用户。
但是,一些(罕见的)操作系统,通常在服务器等工业级设备中,可能会使用CR
, LF-CR
, 或其他完全不同的东西, 这就是为什么第二种方法中有这么多字符的原因, 所以如果你 需要 代码与 兼容每个系统,`你将需要第二种,或者最好是第三种方法。
这里有一个有用的方法来测试你的模式在哪里失败:
String content = "..."; //Replace "..." with your content.
String patternString = "..."; //Replace "..." with your pattern.
String lastPatternSuccess = "None. You suck at Regex!";
for (int i = 0; i <= patternString.length(); i++) {
try {
String patternSubstring = patternString.substring(0, i);
Pattern pattern = Pattern.compile(patternSubstring);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
lastPatternSuccess = i + " - Pattern: " + patternSubstring + " - Match: \n" + matcher.group();
}
} catch (Exception ex) {
//Ignore and jump to next
}
}
System.out.println(lastPatternSuccess);
以下正则表达式在测试 here 时成功运行,但是当我尝试将其实现到我的 Java 代码中时,它不会 return 匹配。它使用否定前瞻来确保 MAIN LEVEL
和 Bedrooms
之间不会出现换行符。为什么它在 Java 中不起作用?
正则表达式
^\s*\bMAIN LEVEL\b\n(?:(?!\n\n)[\s\S])*\bBedrooms:\s*(.*)
Java
pattern = Pattern.compile("^\s*\bMAIN LEVEL\b\n(?:(?!\n\n)[\s\S])*\bBedrooms:\s*(.*)");
match = pattern.matcher(content);
if(match.find())
{
//Doesn't reach here
String bed = match.group(1);
bed = bed.trim();
}
content
只是从文本文件中读取的字符串,其中包含上面链接的演示中显示的确切文本。
File file = new File("C:\Users\ME\Desktop\content.txt");
content = new Scanner(file).useDelimiter("\Z").next();
更新:
我更改了我的代码以包含多行修饰符 (?m)
,但它打印出 "null".
pattern = Pattern.compile("(?m)^\s*\bMAIN LEVEL\b\n(?:(?!\n\n)[\s\S])*\bBedrooms:\s*(.*)");
match = pattern.matcher(content);
if(match.find())
{ // Still not reaching here
mainBeds=match.group(1);
mainBeds= mainBeds.trim();
}
System.out.println(mainBeds); // Prints null
这是行分隔符。您正在寻找 \n
,但您的文件实际上使用 \r\n
。如果您是 运行 Java 8,则可以将代码中的每个 \n
更改为 \R
(通用行分隔符)。对于 Java 7 或更早版本,使用 \r?\n
.
问题:
如 Line-Separators
格式 (\r\n
) 与模式指定的格式 (\n
):
原码:
Pattern.compile("^\s*\bMAIN LEVEL\b
\n
(?:(?!
\n\n
)[\s\S])*\bBedrooms:\s*(.*)");
注:\r
和\n
代表什么意思,\r\n
和\n
的来龙去脉和区别,我在[=]的第二项说明80=]"side notes"节.
解决方案:
Most/all Java 版本:
您可以使用\r?\n
来匹配两种格式,这在大多数情况下 就足够了 .Most/all Java 版本:
可以用\u000D\u000A|[\u000A\u000B\u000C\u000D\u0085\u2028\u2029]
来匹配"Any Unicode linebreak sequence".Java 8 及以后:
你可以使用Linebreak Matcher (\R
)。它相当于第二种方法(上面),只要有可能(Java 8 或更高版本),这是推荐的方法 .
结果代码(第三种方法):
Pattern.compile("^\s*\bMAIN LEVEL\b
\R
(?:(?!
\R\R
)[\s\S])*\bBedrooms:\s*(.*)");
旁注:
可以把
\R\R
换成\R{2}
,可读性更好存在不同格式的换行符并在不同系统中使用,因为早期操作系统从机械打字机(如打字机)继承了 "line-break logic"。
代码中的
\r
表示Carriage-Return,又名CR
。这背后的想法是 return 打字光标到行的开头。代码中的
\n
表示换行,又名LF
。这背后的想法是将打字光标移动到下一行。最常见的换行符格式是
CR-LF
(\r\n
),主要由Windows使用;和LF
(\n
),被大多数类 UNIX 系统使用。这就是为什么 "\r?\n
在大多数情况下 足够 ",并且您可以可靠地将它用于家庭系统-等级用户。但是,一些(罕见的)操作系统,通常在服务器等工业级设备中,可能会使用
CR
,LF-CR
, 或其他完全不同的东西, 这就是为什么第二种方法中有这么多字符的原因, 所以如果你 需要 代码与 兼容每个系统,`你将需要第二种,或者最好是第三种方法。这里有一个有用的方法来测试你的模式在哪里失败:
String content = "..."; //Replace "..." with your content. String patternString = "..."; //Replace "..." with your pattern. String lastPatternSuccess = "None. You suck at Regex!"; for (int i = 0; i <= patternString.length(); i++) { try { String patternSubstring = patternString.substring(0, i); Pattern pattern = Pattern.compile(patternSubstring); Matcher matcher = pattern.matcher(content); if (matcher.find()) { lastPatternSuccess = i + " - Pattern: " + patternSubstring + " - Match: \n" + matcher.group(); } } catch (Exception ex) { //Ignore and jump to next } } System.out.println(lastPatternSuccess);