Java 将纯文本解析为某个结构化对象

Java 将纯文本解析为某个结构化对象,java,parsing,key-value,Java,Parsing,Key Value,我正在解析纯文本并将其转换为键值对。 例如,纯文本: some_uninteresting_thing key1 valueA, some_uninteresting_thing valueB key2 valueD key3 some_uninteresting_thing valueE key4 valueG(valueH, valueI) key5 some_uninteresting_thing 和可能的映射: Map( key1 ->(valueA, valueB

我正在解析纯文本并将其转换为键值对。 例如,纯文本:

some_uninteresting_thing
key1 valueA, some_uninteresting_thing  valueB
key2 valueD
key3 some_uninteresting_thing  valueE 
key4 valueG(valueH, valueI)
key5 some_uninteresting_thing 
和可能的映射:

 Map(

 key1 ->(valueA, valueB,valueC), 
 key2 ->(valueD, valueE),
 key3 ->(valueF)
 key4 ->(valueH, valueI)

 ...
 )
结果将是:

key1 ->(valueA, valueB)
key2 ->(valueD)
key4 ->(valueH, valueI)

(键5不应该被映射,因为它没有合适的值。正如您所看到的,纯文本是宽松的。什么java库可以帮助处理这个问题?

您可以使用解释器和生成器


解释器解析源代码并识别传递给构建器的键和值,构建器构造您想要的任何数据结构。

如果您熟悉正式语言、标记化/语法等,您可以使用解析器生成器,.JavaCC获取您编写的语法文件并生成解析的java代码将文本文件转换为一系列令牌或sytax树。Maven和Ant的插件可以帮助将这个附加源集成到您的构建中

对于一个只运行时的解决方案,有一个,我已经使用了它并取得了很好的效果(我怀疑它没有JavaCC那么快,但对于我来说,性能还不错)

还有,它使用语法文件将纯文本转换为XML

一种替代方法是使用正则表达式和
StringTokenizer
的特别混合

在解析器项目或正则表达式准备就绪的情况下,您的一般方法如下:

  • 为纯文本文件编写语法。缺少有关纯文本格式的某些详细信息,但您可以简单地使用
    BufferedReader.readLine()
    读取文件的行,并使用
    StringTokenizer
    将行拆分为空格和逗号处的子字符串
  • 从解析器获得的字符串、用作键的第一个字符串以及后续字符串都是值,可以添加到映射中。例如,在伪代码中

    Map>Map=newhashmap>(); 每行{ 列表标记=…;//拆分行的结果 String key=tokens.get(0); add(key,tokens.sublist(1,tokens.size()); }

    即使解析器没有过滤不感兴趣的文本,它也会在以后被过滤

  • 使用上述项目构建一个解析器,以解析映射文件格式。同样,您可以使用正则表达式和StringTokenizer构建一个简单的解析器。使用解析器构建映射。映射具有与上述相同的签名,即
    map。

  • 最后,根据允许的值映射过滤输入映射

  • 像这样的

       Map<String,List<String>> input = ...; // from step 1.
       Map<String,List<String>> allowed = ...; // from step 3.
       Map<String,List<String>> result = new HashMap<String<list<String>>(); // the final map
       for (String key : input.keySet()) {
          if (allowd.contains(key)) {
             List<String> outputValues = new ArrayList();
             List<String> allowedValues = allowed.get(key);
             List<String> inputValues = input.get(key);
             for (String value: inputValues) {
                if (allowedValues.contains(value))
                    outputValues.add(value);
             }
             if (!outputValues.isEmpty())
                output.put(key, outputValues);
          }
       }
       // final result in filter
    
    映射输入=…;//来自步骤1。
    允许映射=…;//来自步骤3。
    
    Map result=new HashMap应将类似“key1 valueA、valueB、valueC”的行映射到1个键/值对(“key1'=>“valueA、valueB、valueC”)或3个键/值对(“key1'=>“valueA”和“key1'=>“valueB”和“key1'=>“valueC”)?您的代码应该如何处理示例的第一行?
    某个无趣的东西
    是没有值的键还是什么?在处理最后一行时,应该如何考虑这一点?如何区分“无趣”文本和“有趣的文本”。例如,如果第一行是“it's life,Jim”这是无趣的,还是关键=“这是”,valueA=“生活”,valueB=“吉姆”?@Eric Eijkelenboom不要紧,我两者都能应付situations@CarlSmotricz不应该映射任何内容,解析器继续解析输入