【问题标题】:How to extract data from a text file如何从文本文件中提取数据
【发布时间】:2012-12-20 10:54:52
【问题描述】:

我需要解析一些大文本文件并提取 Display name 和 area code,前提是它与以下模式匹配:

  • 行以display name 开头(任意数量的单词,但不能包含数字或特殊字符)
  • 后跟 6 位数字(可以包含空格)
  • 后跟#text标签

输入文件

John doe 123 456 #text some text
Test 123456 #text
Test$test 123456 #text
Test123 345678 #text
Test 123 #test
Test 123456 #test1
Test 123g45 #test

输入和预期输出

John doe 123 456 #text some text
Display name: John doe
Area code: 123 456

Test 123456 #text
Display name: Test
Area code: 123456

Test$test 123456 #text
Invalid, display name contains special character

Test123 345678 #text
Invalid, display name contains digits

Test 123 #test
Invalid, area code contains only 3 digits

Test 123456 #test1
Invalid, contains invalid tag

Test 123g45 #test
Invalid, area code contains letters

等等

我知道如何打开文本文件并逐行读取,但是在编写正则表达式时遇到了麻烦。

这是我尝试过的:

private static void Main(string[] args)
{
    string text = "John Doe 123 45 #text Lorem ipsum dolor :)";
    string pattern = @"(\w+)*([0-9]{2,5}).([0-9]{2,5}).#text";
    Match match = Regex.Match(text, pattern, RegexOptions.IgnoreCase);

    if (match.Success)
    {
        string key = match.Groups[0].Value;
        Console.WriteLine(key);
    }
}

编辑:

这里有更多解释

显示名称
显示名称可以包含任意数量的单词,例如 John Michael Smith 是有效的,因为 John 是名字,Michael 是中间名,Smith 是姓氏。 Šljaker 也是有效的显示名称,因为它是某人的昵称,并且可能包含非英文字符。但是带有数字的名称是无效的,例如。 John1。为什么?这是我们的业务规则,没有数字 :) 我猜\w 可以在这里工作,而a-zA-Z 不会,因为它不会覆盖非英文字母。

区号
业务规则很简单:它必须包含 6 个数字,我们不关心它们的格式。 所有这些都是有效的区号:123456、12 34 56、1234 56 等。Regex 不需要修剪空格,我会在代码中处理。

任何帮助将不胜感激!

【问题讨论】:

  • 我不明白你到底需要提取什么(对于你的例子,你想得到什么结果?)
  • @Superbest,我已经编辑了我的问题,但显然我的正则表达式非常错误:(
  • 哦,我假设您的文本文件仅由这种行组成:John doe 123 456 #text some text, Test 123456 #test1 ?
  • @aurel.g,是的,没错。在示例中,我展示了该行的外观,所需的输出是什么,或者该行包含无效数据的原因。
  • @šljaker:我们可以假设显示名称是什么?

标签: c# regex


【解决方案1】:

输入的规范写一个合适的正则表达式还是有点模糊。在编写正则表达式之前,有必要先了解一下规范,或者至少做出适用于您当前数据集的假设。

这是我写的正则表达式,正则表达式将验证整行。假设稍后出现。

^([a-zA-Z ]+)(?<! ) +((?:[0-9] *){6}) *#text( .*)?$

我只允许输入中的空格(ASCII 32)。如果您想允许制表符和其他空白字符,您可以用\s 替换正则表达式中的空格。

([a-zA-Z ]+)(?&lt;! ) +:匹配并捕获显示名称。显示名称中只允许使用英文字母和空格。 (?&lt;! ) 用于抑制捕获组的尾随空间;它还有一个不允许名称只有空格的效果。如果要允许 Unicode 中的任何字母匹配,请使用 [\p{L} ]+ 代替 [a-zA-Z ]+。

((?:[0-9] *){6}):正好是 6 个十进制数字,由任意数量的空格分隔。由于在此之前匹配了 1 个或多个 +,因此它不会允许数字粘在显示名称上。

 *#text( .*)?:我允许数字粘在标签上(例如Name 123456#text dfsjhdf);将其更改为 +#text( .*)? 以禁止此操作。如果有更多评论,( .*)? 确保#text 后面有一个空格,或者#text 后面没有任何内容(例如Name 123456 #text)。

从此正则表达式中捕获的文本将:

  • 显示名称:可能包含过多的前导空格和中间空格,但没有尾随空格。至少一个英文字母。
  • 区号:包含正好 6 位数字。中间可能有任意空格,因此您可能需要处理匹配的字符串。

【讨论】:

  • 非常感谢!您的 regex 返回此文本 John Doe Smith 12 3456 #text3 Test 的匹配项,即使它包含 text3 标记而不仅仅是 text 标记。
  • @šljaker:编辑了帖子。
【解决方案2】:

您可以将正则表达式模式替换为以下内容:

@"^([\D]+)\s*((?:\d\s*?){6})\s*\#text\s*(.*)$"

按顺序搜索

  • 非数字序列(第 1 组)
  • 后跟任意数量的空格
  • 后跟正好 6 个数字,每个数字后跟可选的空格(第 2 组)
  • 后跟任意数量的空格和文字“#text”,后跟可选的空格
  • 接下来是线路的其余部分(第 3 组)

由于这是针对多行进行评估的,因此请考虑添加 RegexOptions.Compiled 标志(即:RegexOptions.IgnoreCase | RegexOptions.Compiled)。

显示名称存储为match.Groups[1].Value;区号为match.Groups[2].Value,文字为match.Groups[3].Value。

【讨论】:

  • 谢谢!您的正则表达式返回此文本 John Doe Smith 12 3456 #text3 Test 的匹配项,即使它包含 text3 标记而不仅仅是 text 标记
  • 正则表达式将允许;;;;; 123456 #text等无效情况
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-12-20
  • 1970-01-01
  • 2011-04-20
  • 1970-01-01
相关资源
最近更新 更多