【问题标题】:How to extract fields from a text line that has no constant deliminator?如何从没有常量分隔符的文本行中提取字段?
【发布时间】:2010-03-04 07:24:47
【问题描述】:

从每个字段之间没有明确分隔符(分隔符)的每一行中提取每个字段的最佳方法是什么?

这是我需要提取其字段的行示例:

3/3/2010 11:00:46 AM                      BASEMENT-IN          
3/3/2010 11:04:04 AM 2, YaserAlNaqeb      BASEMENT-OUT         
3/3/2010 11:04:06 AM                      BASEMENT-IN          
3/3/2010 11:04:18 AM                      BASEMENT-IN          
3/3/2010 11:14:32 AM 4, Dhileep              BASEMENT-OUT         
3/3/2010 11:14:34 AM                      BASEMENT-IN          
3/3/2010 11:14:41 AM                      BASEMENT-IN          
3/3/2010 11:15:33 AM 4, Dhileep           BASEMENT-IN          
3/3/2010 11:15:42 AM                      BASEMENT-IN          
3/3/2010 11:15:42 AM                      BASEMENT-IN          
3/3/2010 11:30:22 AM 34, KumarRaju        BASEMENT-IN          
3/3/2010 11:31:28 AM 39, Eldrin           BASEMENT-OUT         
3/3/2010 11:31:31 AM                      BASEMENT-IN          
3/3/2010 11:31:39 AM                      BASEMENT-IN          
3/3/2010 11:32:38 AM 39, Eldrin           BASEMENT-IN          
3/3/2010 11:32:47 AM                      BASEMENT-IN          
3/3/2010 11:32:47 AM                      BASEMENT-IN          
3/3/2010 11:33:26 AM 34, KumarRaju        BASEMENT-OUT         
3/3/2010 11:33:28 AM                      BASEMENT-IN    

每行有 6 个字段,其中一些可以为空。解决这个问题的最佳方法是什么?

  • 我正在使用 Java

01版

  • 字段 5 可以为空(但在所有情况下都应识别其存在)
  • 空格数量可以改变
  • 最后一句话可以改变

【问题讨论】:

  • 您的示例似乎是固定长度的,不是吗?
  • 名称(字段 5)可以更改为任意长度。

标签: java text extract field delimiter


【解决方案1】:

您可以按列号去除日期和 BASEMENT-FOO 数据,因为它们总是出现在行中的同一点。然后您可以根据逗号拆分余数。是否需要处理转义的逗号 \ 或引号中的逗号 "foo, bar" 取决于您和您的业务需求。

【讨论】:

  • 正是我要回答的问题。对我来说,它看起来像是一个固定格式的文件。
  • 字段“名称”(字段 5)的空格数可以更改。我不能指望列号。
  • @MAK 如果是这样的话,如果显示的名称如此之大以至于将 BASEMENT-FOO 推到右侧,您的示例会更清晰。因为你让它看起来好像 BASEMENT-FOO 总是在同一列中。
  • 你说得对,我刚刚更新了我的问题。很抱歉造成混乱。
【解决方案2】:

对我来说似乎有 3 个元字段:

3/3/2010 11:32:38 AM 39, Eldrin           BASEMENT-IN          
3/3/2010 11:32:47 AM                      BASEMENT-IN 

MF1:3/3/2010 11:32:38 AM

MF2:39, Eldrin

MF3:BASEMENT-IN

其中 MF2 是可选的。我的分隔符是:

MF1 直到 [AM|PM]

MF2 号码,除 BASEMENT-*以外的任何号码

MF3 地下室-*

我不太擅长正则表达式,但我会将这 3 个组提取为类似

(anything)(AM|PM)(number,anything)?(BASEMENT-anything)

在哪里?表示可选组。

【讨论】:

    【解决方案3】:

    你可以这样做:

    • 将整行读取为字符串。
    • 在空格(\s+)上分割读取行。你应该得到 5 或 6 件。
    • piece0、piece1 和 piece2 将是 日期、时间和上午/下午。
    • 检查piece3是否有编号:如果有 然后读下一段作为名字
    • 最后一块是地下室的东西。
    • 将字符串中的片段转换为说 日期、时间、int 根据需要。

    【讨论】:

    • 我不确定当(字段 5)为空时这会起作用..会吗?
    • @MAK:你得稍微修改一下。如果您确定最后一块将以“BASEMENT”作为前缀并且您不会有以“BASEMENT”开头的名称:)那么如果您发现一个数字是piece3,您可以查看下一块是否实际上是一个名称.
    • 我希望它会那么简单:) 没有保证最后一个字段以常量表达式开头。
    • @MAK:我明白了。但是您必须找到一种将名称与最后一个字段区分开来的方法。名称之类的东西不会全部大写,最后一个字段将全部大写。
    • hmmm...似乎最后一个词总是大写字母...我认为这会起作用。但是难道没有其他方法可以不传递最后一个单词字母的大小写吗?
    【解决方案4】:

    找出每一行中空白字符与非空白字符相邻的列,然后对这些数字进行统计分析:每一行或几乎每一行出现的那些很可能是字段边界。

    与字母相邻的标点符号类似,但通常无法猜测 a - 或 a , 是否用于分隔字段。如果它出现在每一行的相同位置,它可能是一个分隔符,但在诸如 D-FL R-TX D-NY 之类的事物列表中它可能不是。所以对于任意数据不可能有全自动的解决方案。

    【讨论】:

      【解决方案5】:

      由于每个字段都非常不同(至少在您上面粘贴的示例中),您可以这样做:

      1. 将字符串拆分为标记。
      2. 通过正则表达式模式运行标记化数组的每个元素。

      【讨论】:

      • 数据可以为空的字段5怎么办?
      【解决方案6】:

      您可以使用 Commons Lang 中的 Strtokenizer 并指定多个分隔符进行拆分:

      StrMatcher 支持许多内置类型。

      StrTokenizer(char[] input, StrMatcher delim) 
      

      例如

      StrMatcher delims = StrMatcher.charSetMatcher(new char[] {' ', ',', '\n'});
      StrTokenizer str = new StrTokenizer(match.toString(), delims);
      while (str.hasNext()) {
          System.out.println("Token:[" + str.nextToken() + "]");
      }
      

      将给出(来自上面的示例):

      Token:[3/3/2010]
      Token:[11:00:46]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:04:04]
      Token:[AM]
      Token:[2]
      Token:[YaserAlNaqeb]
      Token:[BASEMENT-OUT]
      Token:[3/3/2010]
      Token:[11:04:06]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:04:18]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:14:32]
      Token:[AM]
      Token:[4]
      Token:[Dhileep]
      Token:[BASEMENT-OUT]
      Token:[3/3/2010]
      Token:[11:14:34]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:14:41]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:15:33]
      Token:[AM]
      Token:[4]
      Token:[Dhileep]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:15:42]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:15:42]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:30:22]
      Token:[AM]
      Token:[34]
      Token:[KumarRaju]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:31:28]
      Token:[AM]
      Token:[39]
      Token:[Eldrin]
      Token:[BASEMENT-OUT]
      Token:[3/3/2010]
      Token:[11:31:31]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:31:39]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:32:38]
      Token:[AM]
      Token:[39]
      Token:[Eldrin]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:32:47]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:32:47]
      Token:[AM]
      Token:[BASEMENT-IN]
      Token:[3/3/2010]
      Token:[11:33:26]
      Token:[AM]
      Token:[34]
      Token:[KumarRaju]
      Token:[BASEMENT-OUT]
      Token:[3/3/2010]
      Token:[11:33:28]
      Token:[AM]
      Token:[BASEMENT-IN]
      

      【讨论】:

      • 但是我的多重分隔符是什么?空间数量可以改变。
      • 空格数量未确定,部分情况下第5栏可以为空。
      • 是的,没关系,它会按照上面的例子工作(我将你的片段转储到一个示例程序中)运行它并且它标记化很好......
      • 不错!但我需要为空字段返回一个空(或一个空格)令牌以保持字段顺序。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-10-17
      • 2018-05-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-03-29
      相关资源
      最近更新 更多