Java 有没有一种简单的方法可以将此文本解析为地图
我收到如下服务的回复。如何将其解析为Java 有没有一种简单的方法可以将此文本解析为地图,java,regex,algorithm,parsing,groovy,Java,Regex,Algorithm,Parsing,Groovy,我收到如下服务的回复。如何将其解析为映射?我首先想到在空白处拆分,但它不起作用,因为值可能包含空格,例如,在下面的响应中查看SA键的值 我想到的一个选择是在空白处拆分,前提是前面的字符是双引号。但不知道如何为此编写正则表达式 TX=“0000000000 10800001830001”FI=“”OS=“8”CI=“QU01SF1S2032”AW=“SSS”SA=“1525迎风大厅”在引号处解析。您甚至可以使用正则表达式来查找每个键/值对,假设每个值都在引号中。我唯一的问题是,如果一个值包含嵌入的
映射
?我首先想到在空白处拆分,但它不起作用,因为值可能包含空格,例如,在下面的响应中查看SA键的值
我想到的一个选择是在空白处拆分,前提是前面的字符是双引号。但不知道如何为此编写正则表达式
TX=“0000000000 10800001830001”FI=“”OS=“8”CI=“QU01SF1S2032”AW=“SSS”SA=“1525迎风大厅”在引号处解析。您甚至可以使用正则表达式来查找每个键/值对,假设每个值都在引号中。我唯一的问题是,如果一个值包含嵌入的引号,那么规则是什么?(它们是使用“\”或类似的方式逃逸的吗?不管怎样,下面的内容中目前没有考虑到这一点…) 例如:
(\w+)="([^"]*)"
这甚至会为您提供组#1和#2,它们可以分别用于提供键和值
使用Java的Matcher.find()
方法在一个循环中运行它,直到找到所有对
示例代码:
String input = "TX=\"0000000000108000001830001\" FI=\"\" OS=\"8\" CI=\"QU01SF1S2032\" AW=\"SSS\" SA=\"1525 Windward Concourse\"";
Pattern p = Pattern.compile("\\s*(\\w+)=\"([^\"]*)\"\\s*");
Matcher m = p.matcher(input);
while(m.find()){
System.out.println(m.group(1));
System.out.println(m.group(2));
}
输出:
TX
0000000000108000001830001
FI
OS
8
CI
QU01SF1S2032
AW
SSS
SA
1525 Windward Concourse
虽然我没有使用quoteChar()
功能,但是速度很快。可以找到示例,以及
控制台:
TX=0000000000108000001830001
FI=
OS=8
CI=QU01SF1S2032
AW=SSS
SA=1525 Windward Concourse
Count: 6
0.623 ms
从文本的外观来看,它似乎可能是XML。是这样,还是该文本是服务的原始响应?如果是XML,可以使用Groovy的XmlSlurper轻松解析:
def input = '<root TX="0000000000108000001830001" FI="" OS="8" CI="QU01SF1S2032" AW="SSS" SA="1525 Windward Concourse"></root>'
def xml = new XmlSlurper().parseText(input)
def map = xml.attributes()
map
的结果会和以前一样。Geez,只需使用单引号;它的标签是Groovy:)@DaveNewton-我们将把它作为操作练习:-)@ziesemer-+1。但是我得到了“=”后面的valaue,它用双quoes打印为“0000000000 108000001830001”@Pangea,因为这就是输入中的值。你期待什么?"108000001830001"? 如果是这样的话,您需要将其解析为一个数字-但鉴于上述示例输入和要求,我不确定如何确定哪些值应作为数字处理,哪些值应作为字符串处理。@ziesemer-我问这个问题是因为您在响应中的示例输出不包含双引号。似乎需要使用replaceAll()方法来删除双引号。了解StreamTokenizerI很好,我只需要尝试一下quoteChar()
;我认为这个解决方案过于复杂。除非有很大的性能限制,否则我建议使用一个更简单的解决方案,比如使用正则表达式(如果性能是一个限制,那么应该对它进行分析,看看它是否真的比正则表达式快,我对此表示怀疑)。@epidemian:是的,这就是为什么我引用了一个方便的解决方案。您也可以这样做:defmap=(匹配为列表).collectEntries{[(it[1]):it[2]}
@tim_-yates Nice!我尝试在match
对象上调用collectEntries
,但它没有该方法,只有标准的迭代方法。我没有想到先把它转换成一个列表。顺便说一句,一个inject
也可以完成这个技巧=D
def input = '<root TX="0000000000108000001830001" FI="" OS="8" CI="QU01SF1S2032" AW="SSS" SA="1525 Windward Concourse"></root>'
def xml = new XmlSlurper().parseText(input)
def map = xml.attributes()
def input = 'TX="0000000000108000001830001" FI="" OS="8" CI="QU01SF1S2032" AW="SSS" SA="1525 Windward Concourse"'
def match = input =~ /(\w+)="([^"]*)"/
def map = [:]
match.each {
map[it[1]] = it[2]
}