与ungreedy匹配的问题

时间:2016-01-28 09:22:37

标签: php regex

在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)

将我的评论转化为答案:重点是模式中有贪婪的子模式:.*{0,20}。它们应该变成 lazy 子模式,否则,你捕获的文本只会包含1个符号(左贪婪的子模式"狼吞虎咽"尽可能多,并且不会让小组旁边的它捕获超过1个符号,因为它们至少需要一个符号)。

请参阅IDEONE demo,使用

$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))

请参阅regex demoIDEONE demo