我还面临Java的matcher的其他问题。我正在尝试使用regex匹配JSON的内容,而不使用外部库。我的JSON如下所示:
[
{
"FIRST":"Tom",
"LAST":"Hanks",
"SUFFIX":""
},
{
"FIRST":"Sammy",
"LAST":"Davis",
"SUFFIX":"Jr."
}
]
然而,我只想匹配前半部分的单词,即在第一个},
匹配之前。我试图创建一个新的模式和匹配器,但我不知道如何进行,也不知道如何在第一次出现},
后打破while循环
Pattern pattern = Pattern.compile(""([^"]*)"");
Matcher matcher = pattern.matcher(loadJSONtoString(fileName).toString());
Pattern pattern2 = Pattern.compile("},");
Matcher matcher2 = pattern2.matcher(loadJSONtoString(fileName).toString());
while(matcher.find())
{
myList.add(matcher.group());
//if matcher2 encounters }. for the first time: break;
}
因为您特别说过不想使用外部库,所以我假设您意识到用正则表达式解析JSON需要很长的路要走,并且应该真正使用JSON解析库。
解决了这个问题,考虑一下JSON解析库本身是如何工作的。它实际上使用了正则表达式。但是,它不是一个正则表达式,而是有许多正则表达式,每个正则表达式都是为了识别JSON语法的某些元素而设计的:带引号的字符串、数字、大括号或大括号等。解析器根据这些正则表达式和从它们构建的东西来定义JSON语法:;字段";是一个带引号的字符串,后跟冒号,后跟一个值;值";是带引号的字符串或数字、数组或对象;对象";是一个左大括号,后面跟着零个或多个字段,后面跟着一个右大括号等。
使用正则表达式编写非常简单的解析器的一个好方法是定义一个正则表达式;代币"您将每个标记定义为一个捕获组,并用"|"分隔它们,以便正则表达式可以匹配其中的任何一个。您可以通过检查匹配的捕获组来确定它找到了哪个令牌。(只有一个匹配。(然后重复使用regex返回令牌,直到得到所需的令牌。
下面是一个可能对您有用的简单正则表达式:
Pattern pattern = Pattern.compile(""([^\"]*)"|({)|(})|(\[)|(\])|(:)|,");
匹配组为:
- 带引号的字符串
- 大括号
- 大括号
- 开口方括号
- 闭合方括号
- 结肠
请注意,逗号没有捕获组,因为这是一种噪音,我们并不太关心它,而且正则表达式中与带引号的字符串匹配的部分不包括引号本身,因此在解析过程中不必删除引号。
您需要构建一个函数,将此正则表达式应用于字符串的其余部分(即尚未解析的内容(,然后在匹配组上循环,并返回匹配组的编号及其内容。对于某些匹配,内容不会那么有趣(如果它与冒号匹配,内容将始终是冒号(,但对于带引号的字符串,内容将是字符串本身。
假设有一个名为JsonScanner
的类,它有两个方法:
getNextToken
应用正则表达式并返回令牌的编号(即匹配组的编号(getContent
返回上次匹配的内容
现在你可以反复调用这些:
JsonScanner scanner(text);
scanner.getNextToken(); // should return '[' token
scanner.getNextToken(); // should return '{' token
scanner.getNextToken(); // should return quoted string
scanner.getContent(); // will return "FIRST"
etc.
实际上,您应该检查返回值是否符合预期,如果不是,则抛出错误。
一旦读取了第一个对象(scanner.getNextToken()
返回"}"标记(,就可以停止扫描。
请注意,这是一个非常简单的实现。例如,带引号的字符串regex不处理字符串中的转义字符。如果您想真正验证JSON,您还必须返回逗号标记,并确保逗号使用正确。但这只是一般的想法。我自己也使用这种策略编写了简单的解析器。
J2EE实际上包含一个名为JsonParser
的类,它基本上为您实现了这一策略。它包含一个next
方法,该方法返回一个标识令牌和内容的Event
。
这是一个使用类似方法的人,只是他不是使用一个带有一堆捕获组的正则表达式,而是使用一堆单独的正则表达式并依次应用每个正则表达式,直到一个匹配为止。