有没有一种简单的方法将这段文本解析为Map?

7
我从服务中收到以下响应。 如何将其解析为Map?我最初考虑在空格处分割,但这不起作用,因为值可能包含空格,例如请查看下面响应中SA键的值。
我想到的一个选项是在空格处分割,前一个字符是双引号 provided 。 不确定如何编写此正则表达式。
TX =“0000000000108000001830001” FI =“” OS =“8” CI =“QU01SF1S2032” AW =“SSS” SA =“1525 Windward Concourse”
3个回答

4

引号解析。您甚至可以使用正则表达式查找每个键/值对,假设每个值都在引号中。我的唯一问题是,如果一个值包含嵌入的引号,规则是什么?(它们是否使用“\”进行转义等?无论如何,以下内容目前没有考虑到...)

例如:

(\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

2
天啊,只需使用单引号;它被标记为Groovy :) - Dave Newton
@DaveNewton - 我们将把这留给OP作为练习。 :-) - ziesemer
@ziesemer - +1。但是我在等号后面打印的值带有双引号,如"0000000000108000001830001"。 - Aravind Yarram
@Pangea - 因为这就是输入中的内容。你期望得到什么?“108000001830001”吗?如果是这样,你需要将其解析为数字 - 但考虑到上面的示例输入和要求,我不确定你如何确定哪些值应该被处理为数字,哪些应该保留为字符串处理。 - ziesemer
@ziesemer - 我问这个问题是因为你在回复中的示例输出不包含双引号。看起来需要使用replaceAll()方法来删除双引号。 - Aravind Yarram
@ziesemer - 更新最新代码后,它不包含双引号。 - Aravind Yarram

3

从文本来看,它似乎可能是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()

The map变量将会是[CI:QU01SF1S2032, AW:SSS, TX:0000000000108000001830001, OS:8, FI:, SA:1525 Windward Concourse]
如果这不是一个XML,你可以按照ziesemer的答案使用正则表达式。他答案的更加优化的版本可以生成一个Map
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]
}
map 的结果与之前相同。

你也可以这样做:def map = ( match as List ).collectEntries { [ (it[1]):it[2] ] } - tim_yates
@tim_yates 不错!我尝试在match对象上调用collectEntries,但它没有这个方法,只有标准的迭代方法。我没想到先将其转换为List。顺便说一下,inject也可以完成这个技巧=D - epidemian

2

StreamTokenizer 是快速的,尽管我没有使用 quoteChar() 功能。可以在 这里这里这里 找到示例。

控制台:

TX=0000000000108000001830001
FI=
OS=8
CI=QU01SF1S2032
AW=SSS
SA=1525 Windward Concourse
Count: 6
0.623 ms

代码:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.StringReader;

/** @see https://dev59.com/1F_Va4cB1Zd3GeqPR0qp */
public class TokenizerTest {

    private static final String s = ""
        + "TX=\"0000000000108000001830001\" FI=\"\" OS=\"8\" "
        + "CI=\"QU01SF1S2032\" AW=\"SSS\" SA=\"1525 Windward Concourse\"";
    private static final char equal = '=';
    private static final char quote = '"';
    private static StreamTokenizer tokens = new StreamTokenizer(
        new BufferedReader(new StringReader(s)));

    public static void main(String[] args) {
        long start = System.nanoTime();
        tokenize();
        long stop = System.nanoTime();
        System.out.println((stop - start) / 1000000d + " ms");
    }

    private static void tokenize() {
        tokens.ordinaryChar(equal);
        tokens.quoteChar(quote);
        try {
            int count = 0;
            int token = tokens.nextToken();
            while (token != StreamTokenizer.TT_EOF) {
                if (token == StreamTokenizer.TT_WORD) {
                    System.out.print(tokens.sval);
                    count++;
                }
                if (token == equal) {
                    System.out.print(equal);
                }
                if (token == quote) {
                    System.out.println(tokens.sval);
                }
                token = tokens.nextToken();
            }
            System.out.println("Count: " + count);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

了解StreamTokenizer很有用。 - Aravind Yarram
我必须尝试使用quoteChar();更多内容请见上文。 - trashgod
我认为这个解决方案过于复杂。除非有很大的性能限制,否则我建议采用更简单的解决方案,比如使用正则表达式(如果性能是一个限制因素,那么应该对其进行分析以确定它是否真的比正则表达式更快,但我怀疑这一点)。 - epidemian
@epidemian:是的,这就是为什么我引用了一个方便的基准测试 - trashgod

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接