【问题标题】:Parsing Plain Text Table解析纯文本表
【发布时间】:2014-07-07 16:17:53
【问题描述】:

我正在尝试以纯文本格式解析表格。该程序是使用 C# 在 Visual Studio 中编写的。我需要解析表并将数据插入数据库。

下面是我将阅读的示例表:

ID    Name          Value1        Value2         Value3       Value4  //header
1     nameA         3.0           0.2            2            6.2
2     nameB
3     nameC         2.9                          3.0          7.3
4     nameD         1.5           3.0            1.8          1.1
5     nameE
6     nameF      1.2        2.4          3.3           2.5
7     nameG      3.0        3.2          2.1           4.5
8     nameH                 88           12.4          28.9

在示例中,我需要捕获 id 1、3、4、6、7 和 8 的数据。

我想了两种方法来解决这个问题,但都没有 100% 有效。

方法一:

通过阅读标题,我可以获得每列的起始索引。然后我将使用Substring 收集每一行的数据。

问题:一旦超过某一行(我不知道何时会发生这种情况),列就会移动,Substring 将不再收集正确的数据。 p>

此方法只会收集 1、3 和 4 的正确数据。

方法二:

使用Regex 收集所有匹配项。我希望这可以按此顺序收集 ID、Name、Value1、Value2、Value3、Value4。

我的模式是(\d*?)\s\s\s+(.*?)\s\s\s+(\d*\.*\d*)\s\s\s+(\d*\.*\d*)\s\s\s+(\d*\.*\d*)\s\s\s+(\d*\.*\d*)

问题: 收集的数据向左移动了一些行。例如,在 ID 3 上,Value2 应为空白,但正则表达式将读取 Value2 = 3.0Value3 = 7.3Value4 = blank。 ID 8 也是如此。

问题:

如何读取整个表格并正确解析?

(1) 我不知道值将从哪一行开始移动,并且

(2) 我不知道它会移动多少个单元格以及它们是否一致。

其他信息

表格在 PDF 文件中,我将 PDF 转换为文本文件,以便读取数据。当一个表跨越多个页面时会发生数据移动,但它并不一致。

编辑

以下是一些实际数据:

68                        BENZYL ALCOHOL                               6.0                            0.4           1                  7.4

91                        EVERNIA PRUNASTRI (OAK MOSS)                 34                             3             3                  10

22                        test                                                                        2323          23                 12

【问题讨论】:

  • 值可以有空格吗?
  • 表格中是否有空格(' ')?如果不是,您可以只读取一行并在所有空格处拆分并整理所有空字符串
  • @coolerfarmer 也有同样的想法 - 但不起作用,因为可能有空单元格。所以你不知道如何在 4 列上分配 3 个值。 (除非你建立一些容易出错的逻辑来计算中间的空格来确定这一点。)
  • @dognose 所有数据都用空格(' ')分隔,值和名称都可能有空格。我只收集至少有 1 个值的行
  • @dognose 例如,ID 3 和 ID 8 都有空单元格,但我仍然想收集其他值的数据。

标签: c# regex indexof


【解决方案1】:

好的,给你!使用这个正则表达式模式:

注意:您必须将此匹配到任何一行,而不是整个文档!如果您想为整个文档执行此操作,则必须添加“多行”修饰符(“m”)。您可以通过在正则表达式模式的开头添加(?m) 来做到这一点!

编辑:

您提供了一些真实数据。这是我更新的正则表达式模式:

^(?<id>\d+)(?:\s{2,25})(?<name>.+?)(?:\s{2,45})(?<val1>\d+(?:\.\d+)?)?(?:\s{2,33})(?<val2>\d+(?:\.\d+)?)?(?:\s{2,14})(?<val3>\d+(?:\.\d+)?)?(?:\s{2,19})(?<val4>\d+(?:\.\d+)?)?$

【讨论】:

  • 非常感谢!我尝试了您的正则表达式,它适用于我提供的示例,但是,当我将其插入实际数据时,它不起作用。这是实际数据“68 BENZYL ALCOHOL 6.0 0.4 1 7.4”中的一行,您能解释一下为什么它没有捕获并帮助我修改它吗?
  • 好的,我试试。你能再发几行数据给我,让我用它们测试一下吗?
  • @sora 我更新了我的帖子。如果有效,请报告!
  • 它适用于我正在使用的正则表达式模拟器,我很确定它也适用于我的程序,我将在我的代码中实现它。非常感谢!
  • @sora 我会尝试优化代码!我会回来报告的!
【解决方案2】:

如何将此文件视为固定长度文件,您可以在其中通过索引和长度定义每一列。一旦你定义了你的固定长度的列,你可以用Substring 获取列的值,然后Trim 来清理它。

您可以将所有这些都包含在 Linq 语句中,以投影到匿名类型并过滤您想要的 ID。

类似这样的:

static void Main(string[] args)
{
    int[] select = new int[] { 1, 3, 4, 6, 7, 8 };
    string[] lines = File.ReadAllLines("TextFile1.txt");

    var q = lines.Skip(1).Select(l => new {
        Id = Int32.Parse(GetValue(l, 0, 6)),
        Name = GetValue(l, 6, 11),
        Value1 = GetValue(l, 17, 11),
        Value2 = GetValue(l, 28, 13),
        Value3 = GetValue(l, 41, 14),
        Value4 = GetValue(l, 55, 13),
    }).Where(o => select.Contains(o.Id));

    var r = q.ToArray();        
}

static string GetValue(string line, int index, int length)
{
    string value = null;
    int lineLength = line.Length;

    // Take as much of the line as we can up to column length
    if(lineLength > index)            
        value = line.Substring(index, Math.Min(length, lineLength - index)).Trim();

    // Return null if we just have whitespace
    return String.IsNullOrWhiteSpace(value) ? null : value;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-28
    • 2011-04-08
    • 2023-04-05
    • 1970-01-01
    • 2023-03-13
    • 2013-08-15
    • 2013-06-21
    • 1970-01-01
    相关资源
    最近更新 更多