【问题标题】:Using regex to extract variables from a plain-text form letter?使用正则表达式从纯文本格式信函中提取变量?
【发布时间】:2011-02-07 01:50:37
【问题描述】:

我正在寻找一个在 PHP 中使用正则表达式对已粘贴到多行文本框并发送到脚本进行处理的套用信函(当然是已知格式)“逆向工程”的一个很好的例子。

因此,例如,假设 这是原始的纯文本输入(摘自美国农业部新闻稿):

华盛顿,2010 年 4 月 5 日 - 北 美国野牛合作社,新罗克福德, N.D.,机构正在召回 大约 25,000 磅整 牛头含有可能的舌头 没有完全拥有扁桃体 删除,这不符合 要求删除的法规 所有年龄的牛的扁桃体, 美国农业部 食品安全检验服务 (FSIS) 今天宣布。

为清楚起见,下面突出显示了属于变量的字段:

[pr_city=]华盛顿[pr_date=]2010 年 4 月 5 日 - [corp_name=]North 美国野牛合作社[corp_city=]新罗克福德[corp_state=]N.D.,企业正在召回 大约 [amount=]25,000 磅 [product=]整个 牛头含有可能的舌头 没有完全拥有扁桃体 已删除,不符合 要求[reason=]删除的法规 来自所有年龄的牛的扁桃体, 美国农业部 食品安全检验服务 (FSIS) 今天宣布。

我怎样才能有效地提取内容

  • pr_city
  • pr_date
  • 公司名称
  • corp_city
  • corp_state
  • 金额
  • 产品
  • 原因

我的示例中的字段?

任何帮助将不胜感激,谢谢。

【问题讨论】:

  • 我不清楚用户在多行文本框中传递的是什么,是原样的文本还是已经带有 [pr_city=]、[pr_date=] 符号的文本?我问是因为纯文本输入在字段之间包含某种分隔符(如 [pr_city=]、[pr_date=]、...),或者每个字段必须是固定长度,否则我不看看正则表达式或其他任何东西如何能够识别纯文本的不同部分。
  • 如果我不清楚,我深表歉意 - 第一个文本块将是原始文本,第二个文本块突出显示“变量”。谢谢

标签: php regex parsing text-processing


【解决方案1】:

嗯,适用于您的示例的正则表达式可能如下所示(引入换行符以保持该野兽的可读性,需要在使用前删除):

/^(?P<pr_city>[^,]+), (?P<pr_date>[^-]+) - (?P<corp_name>.*?), a 
(?P<corp_city>[^,]+), (?P<corp_state>[^,]+), establishment is 
recalling approximately (?P<amount>.*?) of (?P<product>.*?), 
which is not compliant with regulations that require (?P<reason>.*?), 
the U\.S\. Department of Agriculture\'s Food Safety and Inspection 
Service \(FSIS\) announced today\.$/

所以,在 PHP 中你可以这样做

if (preg_match('/^(?P<pr_city>[^,]+), (?P<pr_date>[^-]+) - (?P<corp_name>.*?), a (?P<corp_city>[^,]+), (?P<corp_state>[^,]+), establishment is recalling approximately (?P<amount>.*?) of (?P<product>.*?), which is not compliant with regulations that require (?P<reason>.*?), the U\.S\. Department of Agriculture\'s Food Safety and Inspection Service \(FSIS\) announced today\.$/', $subject, $regs)) {
    $prcity = $regs['pr_city'];
    $prdate = $regs['pr_date'];
    ... etc.
} else {
    $result = "";
}

这假设了几件事,例如没有换行符,并且输入是整个字符串(而不是必须从中提取这部分的较大字符串)。我试图对法律价值做出一些有意义的假设,但其他输入很有可能会破坏这一点。所以可能需要更多的测试用例。

【讨论】:

  • 优秀。感谢您的快速周转。你介意分解以下表达式吗? (?P[^,]+), (?P[^-]+) - (?P.*?) - 我仍在尝试学习正则表达式。非常感谢。
  • 当然。 (?P&lt;name&gt;...) 表示一个命名的捕获组,因此您可以引用匹配的名称而不是其编号。正则表达式风格的语法相当不一致。 [^,]+ 表示“匹配一个或多个除逗号之外的字符”,.*? 表示“匹配除换行符以外的任意数量的字符,尝试尽可能少地匹配以使整体匹配有效”。
【解决方案2】:

如果周围的文本是不变的,那么像这样的部分正则表达式就可以解决问题:

preg_match('/^(.*?), (.*?)- (.*?), a (.*?), (.*?), establishment is recalling approximately (.*?), which is not compliant with regulations that require (.*?), the U.S. Department of Agriculture's Food Safety and Inspection Service (FSIS) announced today./', $text, $matches);

$matches[1] = 'WASHINGTON';
$matches[2] = 'April 5, 2010';
$matches[3] = ... etc...

如果周围的文本发生变化,那么您最终会遇到大量错误匹配、不匹配等...基本上您需要 AI 来解析/理解 PR 版本。

【讨论】:

    【解决方案3】:

    编辑:请忽略这个疯狂的答案,因为其他两个更好。我可能应该删除它,但我会保留它以供参考。

    我有一个可能可行的疯狂想法:通过添加标记从输入构建一个 XML 字符串,然后对其进行解析。它可能看起来像这样(完全未经测试)的代码:

    preg_replace('([^,]*), ([^-]*)- ...etc...', '<pr_city>\1</pr_city><pr_date>\2</pr_date> ...etc...');
    

    之后解析 XML 是一个不必要的复杂过程,最好留给 PHP 文档:http://www.php.net/manual/en/function.xml-parse.php

    您也可以考虑使用此方法将其转换为 JSON,然后使用 json_decode() 对其进行解析。无论如何,您必须考虑当" 标记和&gt; 符号出现在输入中时会发生什么。

    一次只匹配和删除一段文本可能更容易。

    【讨论】:

    • 谢谢 - 我会看看那个链接。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-15
    相关资源
    最近更新 更多