非贪婪匹配的问题

3
在PHP中,我正在使用以下正则表达式匹配此处的文本http://pastebin.com/PfjEgQpd
preg_match('#(.*(?s))(particella |particelle |p\.|part\.|p |part |mappale |mapp\.|mapp |n\.|\*) *(\d+[\d /\p{Pd}]*)($|.{0,20}(?s)(graffati|particella |particelle |p\.|.*part\.|p |part |mappale |mapp\.|mapp |n\.|subalterno |subalterni |sub\.|s\.|sub |s |\bcat\b|\bcategoria\b|\brendita\b|\bvani\b|\bconsistenza\b|\bR\.C\.\b))#i', $txt, $matches, PREG_OFFSET_CAPTURE, $offset)

使用$offset = 944,我在$matches中得到了以下输出。

我期望匹配的是1184,但实际上匹配的是4。 我尝试了使用(?sU),但没有成功。

$matches = array(6) {
  [0]=>
  array(2) {
    [0]=>
    string(59) "* 1184 sub.702, vioolo San Vincenzo n.4, piano T, Categoria"
    [1]=>
    int(1226)
  }
  [1]=>
  array(2) {
    [0]=>
    string(36) "* 1184 sub.702, vioolo San Vincenzo "
    [1]=>
    int(1226)
  }
  [2]=>
  array(2) {
    [0]=>
    string(2) "n."
    [1]=>
    int(1262)
  }
  [3]=>
  array(2) {
    [0]=>
    string(1) "4"
    [1]=>
    int(1264)
  }
  [4]=>
  array(2) {
    [0]=>
    string(20) ", piano T, Categoria"
    [1]=>
    int(1265)
  }
  [5]=>
  array(2) {
    [0]=>
    string(9) "Categoria"
    [1]=>
    int(1276)
  }
}
$offset = int(944)
1个回答

0

将我的评论转化为答案:关键在于模式中存在贪婪子模式:.*{0,20}。它们应该被转换为懒惰子模式,否则,您捕获的文本将只包含1个符号(左侧贪婪子模式“吞掉”尽可能多的内容,并且不允许旁边的组捕获超过1个符号,因为它们至少需要一个符号)。

请参见IDEONE演示,使用

$re = '~(.*?(?s))(particella |particelle |p\.|part\.|p |part |mappale |mapp\.|mapp |n\.|\*) *(\d+[\d /\p{Pd}]*)($|.{0,20}?(?s)(graffati|particella |particelle |p\\.|.*part\\.|p |part |mappale |mapp\.|mapp |n\.|subalterno |subalterni |sub\.|s\.|sub |s |\bcat\b|\bcategoria\b|\brendita\b|\bvani\b|\bconsistenza\b|\bR\.C\.\b))~'; 

由于您的模式太脆弱,我对其进行了优化,并在所有地方将 替换为\s,因为您的意图是匹配这些位置中的所有空格:

(?s)(.*?)(particell[ea]\s+|p(?:art)?[.\s]+|mapp(?:(?:ale)?\s+|\.)|n\.|\*)\s*(\d+[\d\s/\p{Pd}]*)($|.{0,20}?(graffati|particell[ae]\s+|p(?:art)?[.\s]+|mapp(?:(?:ale)?\s+|\.)|n\.|subaltern[oi]\s+|s(?:ub)?[.\s]+|\bcat(?:egoria)?\b|\brendita\b|\bvani\b|\bconsistenza\b|\bR\.C\.\b))

请查看正则表达式演示IDEONE演示


什么是偏移量?顺便说一句,你的模式非常脆弱,可能会导致灾难性的回溯。为了修复它,我需要知道你尝试使用它来提取什么。 - Wiktor Stribiżew
我在这里也遇到了同样的问题 http://siba.thenetworksolution.it/allegati/H3018500D7FDDE9ACA05671F49F4F3746A69DAF96.1329514.pdf.txt。相同的正则表达式,偏移量为1155,匹配的是“57/1998”,而不是“454”。懒惰子模式在这种情况下无法帮助。我正在尝试提取地籍数据“foglio 1, particella 454, sub.4 e sub.5.”。这是应该匹配“particella”的正则表达式:454。我提供的偏移量是“foglio 1”的偏移量(在我的代码中先用另一个正则表达式匹配)。 - Marco Marsala
жИСиЃ§дЄЇдљ†еПѓдї•дљњзФ®(?s)(.*?)(particell[ea]\s+|p(?:art)?[.\s]|mapp(?:(?:ale)?\s|\.)|n\.|\*)\s*(\d+[\d\s/\p{Pd}]*)($|.{0,20}?(graffati|particell[ae]\s|p(?:art)?[.\s]|mapp(?:(?:ale)?\s|\.)|n\.|subaltern[oi]\s|s(?:ub)?[.\s]|\bcat(?:egoria)?\b|\brendita\b|\bvani\b|\bconsistenza\b|\bR\.C\.\b))гАВжИСдЉШеМЦдЇЖж®°еЉПпЉМеєґе∞ЖеЄЄиІДз©Їж†ЉжЫњжНҐдЄЇеМєйЕНжЙАжЬЙз©ЇзЩље≠Чзђ¶зЪД\sж®°еЉПгАВе¶ВжЮЬеЬ®жЬЂе∞ЊжЈїеК†/uдњЃй•∞зђ¶пЉМжВ®ињШеПѓдї•дљњзФ®еЃГеМєйЕНжЙАжЬЙUnicodeз©Їж†ЉеТМжХ∞е≠ЧгАВ - Wiktor Stribiżew
这并不是那么简单。这些类型的数据在这些文档中可能以许多方式指定,而我正在批处理许多文件。在正则表达式之前和之后有很多逻辑。除了*的贪婪匹配外,它几乎完美。 - Marco Marsala
1
我使用了\s*。顺便说一句,我刚刚解决了这个问题。问题在于第二组中particella后面的空格。 - Marco Marsala
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接