【问题标题】:Perl regex back reference not being greedyPerl 正则表达式反向引用不贪心
【发布时间】:2016-08-26 01:53:08
【问题描述】:

这是一个有效的正则表达式:

/(ANSI|AAMVA) (\d{6})(\d{2})(\d{2})(\d{0,2})((?:DL)|(?:ID))+(.*?)\g{-2}+([^"]+)/

这是一个示例字符串:

"@\n\nANSI 6334290212DL00389199ZO04420478DLDAQ3572928\nDAASMITH, JOHN DOE\nDAG\nDAL4389 NE 47TH AVE\nDAIASHLAND\nDAJOR\nDAK97555      \nDARC   \nDASD         \nDATM     \nDAU504\nDAW180\nDBA12201212\nDBB19780303\n"

我正在尝试匹配分隔符,DLID,它可能会再次出现在字符串中。

我想匹配之前匹配的DLID

问题是,如果我使用 ? 来完成此操作,它就会停止贪婪并更喜欢 0 个匹配项。

我很难过,我是否缺少? 运作方式的基本知识?

编辑:问题不在于提取 JSON 数据,而是解析 msg 位,使用 JSON 没有做任何事情来完成此任务。我将字符串修剪到相关的部分。

@hobbs 的修复有效,因为它让我将 ? 更改为 + 并且仍然不匹配,如果没有任何内容。

有效! :)

/(ANSI|AAMVA) (\d{6})(\d{2})(\d{2})(\d{0,2})((?:DL)|(?:ID))+(.*?)(?:\g{-2}|(?="))+([^"]+)/

【问题讨论】:

  • 欢迎来到 Stack Overlow。您的格式很难阅读。您能否编辑您的问题以包含您尝试解决的实际问题的干净示例?
  • ID 不会出现在您的示例数据中的任何位置。你真正想做什么?
  • 大部分字符串是不相关的。修剪它,显示你得到的输出,并显示你想要的输出。
  • 您的示例字符串看起来非常像 JSON。为什么不将其解析为 JSON?
  • ID 出现在不同的数据中,这就是驾照 (DL) 或 ID 背面的条形码所包含的内容。有很多奇怪的状态和一系列添加有趣边缘情况的版本。

标签: regex perl regex-greedy


【解决方案1】:

问题不在于\g{-2}? 是非贪婪的,而是紧接在它之前的(.*?) 是非贪婪的,而\g{-2}? 无法匹配任何内容,这意味着它可以'不会失败。如果它不能失败,那么它不会强制它之前的组匹配超过 0 个字符。因此,(.*?) 将不匹配任何内容,\g{-2} 将不匹配任何内容,([^"]+) 将匹配所有内容。

我不完全理解您要提取的格式(除了它陈旧且奇怪,让我想起 CIBER 计费记录),但我建议您需要更多锚定以将您的正则表达式的注意力集中在正确的位置,或者您需要升级到适当的格式解析器之类的东西。由于您说您添加了? 来处理分隔符从不出现的情况,因此最快的创可贴修复可能是(?:\g{-2}|(?=")),它断言您要么找到分隔符, 你到了结束报价却没有找到它。

虽然,鲍罗丁的观察也是有效的;最好先解码 JSON,然后使用解码后的 JSON 结构中的字符串,而不是尝试直接在 JSON 上运行正则表达式。在这种情况下,您应该寻找\z(字符串结尾)而不是"

【讨论】:

  • “它既古老又奇怪” 你必须捍卫它。我不知道你的背景是什么,但 OP 的数据是 JSON。它是一种非常有用且常见的简单数据表示,它受 JavaScript 支持,它起源于 Python、Perl、PHP、Java、C 及其家族等。它有自己的MIME 类型application/json,我猜它至少和XML 一样流行。你去哪儿了?
  • @Borodin 我显然不是在谈论 JSON。您对问题或我的回答没有给予足够的重视。
  • 我仔细阅读了您提交的内容。虽然它在您的脑海中可能非常有意义,但您永远不会提到 JSON 并以 “我不完全理解您尝试提取的格式” 开始一个新段落。对我来说,这意味着您对整个 OP 的数据一无所知。 “虽然,鲍罗丁的观察也是有效的” 之后还有一个分号(这些;),表示你不同意我的观点。删除逗号 (,) 并使用冒号 (:),您的帖子的意义将与您的评论一致。
  • 如果先解码json,还需要/s
  • 使匹配成为 \g{-2} 或空字符串是很好的解决方法,它让我在第二个不存在时添加 + 号而不会丢失:),我假设\g{-2}?宁愿匹配 1 而不是 0,但似乎情况并非如此。
【解决方案2】:

您的数据是 JSON,尝试使用正则表达式模式处理它是非常错误的。有非常好的 Perl 模块可以将文本转换为可导航的数据结构

我无法准确理解您需要什么,因为您在谈论 DAID 字符串,而 ID 不会出现在您的示例数据中的任何位置。但是这个简短的程序应该会有所帮助

use strict;
use warnings 'all';
use feature 'say';

use JSON 'decode_json';

my $json = do {
    local $/;
    <DATA>;
};

my $data = decode_json $json;

say $data->{msg};


__DATA__
{"name":"SC","hostname":"tukwila","pid":11,"level":30,"msg":"@\n\nANSI 6334290212DL00389199ZO04420478DLDAQ3572928\nDAASMITH, JOHN DOE\nDAG\nDAL4389 NE 47TH AVE\nDAIASHLAND\nDAJOR\nDAK97555      \nDARC   \nDASD         \nDATM     \nDAU504\nDAW180\nDBA12201212\nDBB19780303\n","time":"2016-04-02T01:09:07.113Z","v":0}

输出

@

ANSI 6334290212DL00389199ZO04420478DLDAQ3572928
DAASMITH, JOHN DOE
DAG
DAL4389 NE 47TH AVE
DAIASHLAND
DAJOR
DAK97555      
DARC   
DASD         
DATM     
DAU504
DAW180
DBA12201212
DBB19780303

【讨论】:

  • 有趣的不是 JSON。当然,这是正确的第一步,但我的理解是,真正的任务是提取数据位,例如00389199ZO04420478.
  • @hobbs:我很抱歉。我错过了你不是 OP
  • @hobbs 是正确的,JSON 的东西在其他地方处理,这是我的问题的相关部分的 ANSI 流。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-03-30
  • 1970-01-01
  • 1970-01-01
  • 2016-02-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多