java - 结合积极的后瞻和前瞻

标签 java regex regex-lookarounds lookbehind

我想从自定义键值协议(protocol)解析数组。看起来像这样

RESPONSE GAMEINFO OK
NAME: "gamelobby"
PLAYERS: "alice", "bob", "hodor"
FLAGS: 1, 2, 3

在 Java 中,字符串看起来像这样(它使用 CRLF 作为换行符):

RESPONSE GAMEINFO OK\\r\\nNAME: \"gamelobby\"\\r\\nPLAYERS: \"alice\", \"bob\", \"hodor\"FLAGS: 1, 2, 3\\r\\n

我想按原样捕获“alice”、“bob”、“hodor”。所以我使用了这个正则表达式,它在 Sublime Text 和 regex101.com 上进行了测试(键不区分大小写)

(?<=(?i:PLAYERS): )([A-Za-z0-9\s\.,:;\?!\n"_-]*)(?=\r\n)

这是 Sublime Text 的屏幕截图(注意:我在这里省略了\r):

enter image description here

当我 try catch 该组时,我也得到了下一行:

Pattern p = Pattern.compile("(?<=(?i:"+key+"): )([A-Za-z0-9\\s\\.,:;\\?!\\n\"_-]*)(?=\\r\\n)");
Matcher matcher = p.matcher(message);
matcher.find();
String value = new String();
try {
    value = matcher.group(); // = "\"alice\", \"bob\", \"hodor\"\\r\\nFLAGS: 1, 2, 3"
} ...

注意:\"\\\" 似乎没有什么区别。

为什么 FLAGS: 1, 2, 3 直到 \\r\\n 才被捕获,而不是在上面的行中?积极的后瞻和前瞻是否可能?首先评估哪个前瞻/后瞻?

编辑:字符串数组的定义是

values        = string*("," WSP string)
string        = DQUOTE *(ALPHA / DIGIT / WSP / punctuation / "\n") DQUOTE
punctuation   = "." / ":" / "," / ";" / "?" / "!" / "-" / "_"

最佳答案

按照你的语法写代码即可。对我来说,语法似乎并不含糊,所以如果你只是遵循它并一点一点地编写你的正则表达式,你就会没事的:

String WHITESPACE_RE = "[ ]"; // Modify this according to your grammar
String PUNCTUATION_RE = "[.:,;?!_-]";
String STRING_RE = "\"(?:[A-Za-z0-9" + WHITESPACE_RE + PUNCTUATION_RE + "\n])*\"";
String VALUES_RE = STRING_RE + "(?:," + WHITESPACE_RE + STRING_RE + ")*";
String PLAYERS_RE = "PLAYERS:" +  WHITESPACE_RE + "(" + VALUES_RE + ")(?=\r\n)";

目前,\r\n 用于检查 PLAYERS 条目末尾的行分隔符。将其更改为您的规范中指定的任何内容。

警告

此解决方案仅适用于解析有效输入。解析无效输入取决于您的恢复算法和行分隔符。

如果行分隔符允许使用 \n 以及 \r\n,则很难从错误中恢复。例如,如果有一个名为 ABC\nFLAGS: 1, 2, 3 的用户(根据语法是允许的),但缺少右双引号,则玩家列表将被破坏,并且您将无法判断 FLAGS: 是上一行的一部分还是不同 header 的一部分。

RESPONSE GAMEINFO OK
NAME: "gamelobby"
PLAYERS: "alice", "bob", "hodor", "ABC
FLAGS: 1, 2, 3
FLAGS: 1, 2, 3

完整示例

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class SO28290386 {
    public static void main(String[] args) {
        String WHITESPACE_RE = "[ ]"; // Modify this according to your grammar
        String PUNCTUATION_RE = "[.:,;?!_-]";
        String STRING_RE = "\"(?:[A-Za-z0-9" + WHITESPACE_RE + PUNCTUATION_RE + "\n])*\"";
        String VALUES_RE = STRING_RE + "(?:," + WHITESPACE_RE + STRING_RE + ")*";
        String PLAYERS_RE = "PLAYERS:" +  WHITESPACE_RE + "(" + VALUES_RE + ")(?=\r\n)";
        System.out.println(PLAYERS_RE);

        String input = "RESPONSE GAMEINFO OK\r\nNAME: \"gamelobby\"\r\nPLAYERS: \"alice\", \"bob\", \"hodor\", \"new\nline\"\r\nFLAGS: 1, 2, 3\r\n";
        System.out.println("INPUT");
        System.out.println(input);

        Pattern p = Pattern.compile(PLAYERS_RE);
        Matcher m = p.matcher(input);
        while (m.find()) {
            System.out.println(m.group(0));
            System.out.println(m.group(1));
        }
    }
}

关于java - 结合积极的后瞻和前瞻,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28290386/

相关文章:

java - 在 Java 中排列输出

javascript - 如何在 Safari 中运行这个积极的 lookbehind 正则表达式

regex - 大写字母的 .NET Regex 负前瞻

java - 解决 axis2 和 OC4J 库冲突

java - 从 Java 访问时,Scala public 变为 private?

php preg_match utf-8 奇怪的行为

php - 使用正则表达式管理电话号码验证漏洞

c - 正则表达式:在两个字符串之间提取与特定单词匹配的文本

java 正则表达式 : negation of a match

java - Retrofit、IGDB Api - 如何正确传递 Api Key?