【问题标题】:Parsing plain text to some structured object将纯文本解析为某个结构化对象
【发布时间】:2010-04-26 12:00:32
【问题描述】:

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

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)

 ...
 )

Amd 结果将是:

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

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

【问题讨论】:

  • 应该像 'key1 valueA, valueB, valueC' 这样的行映射到 1 个键/值对 ('key1' => 'valueA, valueB, valueC') 或 3 个键/值对 ('key1 ' => 'valueA' 和 'key1' => 'valueB 和 'key1' => 'valueC')?
  • 您的代码应该如何处理示例的第一行? some_uninteresting_thing 是没有值的键,还是什么?在处理最后一行时应该如何考虑这一点?
  • 如何区分“无趣”文本和“有趣文本”。例如,如果第一行是“it's life, Jim”,是无趣还是 key="it's", valueA="life", valueB="Jim" ?
  • @Eric Eijkelenboom 没关系,两种情况我都能应付
  • @Carl Smotricz 什么都不应该被映射,解析器继续解析输入

标签: java parsing key-value


【解决方案1】:

如果您熟悉形式语言、标记化/语法等,您可以使用解析器生成器,例如 JavaCC。 JavaCC 获取您编写的语法文件并生成将文本文件解析为一系列标记或语法树的 java 代码。有一些适用于 Maven 和 Ant 的插件可以帮助将这个额外的源代码集成到您的构建中。

对于仅运行时的解决方案,有RunCC,我使用它并取得了很好的效果。 (我怀疑它不如 JavaCC 快,但就我而言,性能还不错。)

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

替代方法是使用正则表达式和StringTokenizer 的临时组合。

有了解析器项目或正则表达式并准备就绪,您的一般方法是这样的:

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

    Map> map = new HashMap>(); 对于每一行{ 列出令牌 = ...; // 分割线的结果 字符串键 = tokens.get(0); map.add(key, tokens.sublist(1, tokens.size()); }

    即使解析器不过滤无意义的文本,稍后也会过滤掉。

  3. 用以上项目构建解析器,解析地图文件格式。同样,您可以使用正则表达式和 StringTokenizer 构建一个简单的解析器。使用解析器构建地图。该地图的签名与上面相同,即Map<String,List<String>>.

  4. 最后,根据允许值映射过滤输入映射。

类似的东西。

   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

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-16
      • 2017-10-26
      • 1970-01-01
      • 1970-01-01
      • 2015-07-26
      相关资源
      最近更新 更多