我想从自定义键值协议解析数组。看起来像这样
RESPONSE GAMEINFO OK
NAME: "gamelobby"
PLAYERS: "alice", "bob", "hodor"
FLAGS: 1, 2, 3
在Java中,String看起来像这样(它使用CRLF作为换行符):
RESPONSE GAMEINFO OK\\r\\nNAME: \"gamelobby\"\\r\\nPLAYERS: \"alice\", \"bob\", \"hodor\"FLAGS: 1, 2, 3\\r\\n
我想按原样捕捉"alice", "bob", "hodor"
。所以我使用了这个regexp,它在Sublime Text和regex101.com上测试过(键不区分大小写)
(?<=(?i:PLAYERS): )([A-Za-z0-9\s\.,:;\?!\n"_-]*)(?=\r\n)
这是Sublime Text的截图(注意:我遗漏了\ r这里):
当我尝试捕获该组时,我也得到了下一行:
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
,但不在上面的行中?积极的外观和前瞻可能吗?首先评估哪个lookhead / lookbehind?
编辑:字符串数组的定义是
values = string*("," WSP string)
string = DQUOTE *(ALPHA / DIGIT / WSP / punctuation / "\n") DQUOTE
punctuation = "." / ":" / "," / ";" / "?" / "!" / "-" / "_"
答案 0 :(得分:1)
根据你的语法编写代码。语法对我来说似乎并不含糊,所以如果你只是按照它来拼写你的正则表达式,你就会好起来的:
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
的用户(根据语法允许),但缺少结束双引号,那么玩家列表将被破坏,您将无法判断是否{{1 }}是前一行的一部分或不同的标题。
FLAGS:
RESPONSE GAMEINFO OK
NAME: "gamelobby"
PLAYERS: "alice", "bob", "hodor", "ABC
FLAGS: 1, 2, 3
FLAGS: 1, 2, 3
答案 1 :(得分:0)
您可以在括号表达式上使用非贪婪的乘数:
(?<=(?i:PLAYERS): )([A-Za-z0-9\s\.,:;\?!\n"_-]*?)(?=\r\n)
当您使用贪心倍数\r\n
时,匹配原因不会停留在*
,因为括号表达式包含\s
。 \s
的定义(根据Pattern
类的文档)是[ \t\n\x0B\f\r]
,因此括号表达式实际上是通过CRLF行终止符和其路径中的其他所有内容,直到它到达整个字符串的结尾。
我想如果您可以明确地防止单词CR出现在引用词列表中,那么另一个可行的解决方案是用明确的\s
替换[\n\t\f ]
,但我&#39我会把它留给你。
非贪婪乘数*?
解决方案有效,因为当正则表达式引擎命中第一个CRLF以满足最终前瞻声明时,它会停止匹配,即使括号表达式可能会吞噬它。
由于网站似乎不支持CR,test code on regex101因字符串包含新行而失败,因此我们无法在那里进行全面测试。但是在Java代码中的真正正则表达式中,前瞻断言需要CRLF才能终止搜索,因此最终会匹配整个引用词列表。