PHP preg_match повторение группы - PullRequest
1 голос
/ 29 марта 2011

У меня есть (php5.2 и 5.3) регулярное выражение, которому необходимо извлечь первые $ x предложений из поста пользователя (который может включать адреса электронной почты и гиперссылки), и мне не удается выяснить, почему (и да, это отвратительное регулярное выражение; я оптимизирую его, когда оно будет работать):

/^(([^.!?]+|(\w+[.@?&=%:])+\w+)+[.!?]+\s){0,4}/

возвращает первые четыре предложения, но

/^(([^.!?]+|(\w+[.@?&=%:])+\w+)+[.!?]+\s){0,5}/

не возвращает совпадений. Насколько я понимаю, {0,5} должно совпадать с предыдущей группой от 0 до 5 раз, и поэтому все равно должно работать, если оно может соответствовать ей только 4 раза.

Может кто-нибудь пролить свет на это поведение?

Обновление: $ x - просто произвольное число; используя {0, $ x} в регулярном выражении. Сообщение фильтруется, чтобы быть предложениями, разделенными одним пробелом. Извините за уродливое выражение ... изучал это уже пару дней, и это заставляет меня задуматься ... Сделал изменения, предложенные sawa. Мой главный вопрос о поведении, и содержание, которому соответствует группа, не должно иметь такого большого значения.

Обновление2: по сути, это то, что я делаю:

function extractSummary($message, $limit) {
  $expr = '/^(([^.!?]+|(\w+[.@?&=%:])+\w+)+[.!?]+\s){0,'.$limit.'}/';
  $msg = preg_replace('/[\x00-\x1f\x80-\xff]/', "\n" strip_tags($message));
  $msg = trim(preg_replace('/(\n|\s| )+/', ' ', $msg)).' ';
  preg_match($expr, $msg, $summary);
  return $summary[0];
}

Предложение (по крайней мере, на мой взгляд, без перехода на территорию НЛП, потому что оно предназначено только для одной функции на сайте) - это что-то до точки, восклицательного знака или вопросительного знака, но точки могут появляться в предложении в виде адрес электронной почты URL. Последняя версия этого регулярного выражения просто насчитывала до 5 периодов и, таким образом, разбивалась по ссылкам и адресам электронной почты.

Обновление 3: Учитывая, что я только что добавил еще более ужасный код, я объясню последнее. Было обнаружено, что в некоторых опубликованных материалах есть непечатаемые символы (например, \ r и т. Д.), Которые не очень хорошо работают с регулярным выражением, поэтому я удаляю непечатные символы с первым preg_replace. Второй заменяет любые дальнейшие группы пробелов одним пробелом, поэтому, мы надеемся, предложения разделены ровно одним пробелом.

Ответы [ 3 ]

0 голосов
/ 29 марта 2011

Я узнаю следующее предложение:

Предложение:

  • кратчайшая последовательность до периода, восклицательного знака или знака вопроса,
  • при желании следует одинарная или двойная кавычка,
  • в обязательном порядке следует пробел или конец строки.

Это требование пробела или конца строки учитывает точки в адресах электронной почты, поскольку точки в адресах электронной почты не отображаются непосредственно перед пробелом или в конце строки.

/[^ ](?:.*?[.!?]['"]*(?= |\z)){0,4}/
0 голосов
/ 29 марта 2011

Эта проверенная функция должна помочь:

function get_sentences($text, $x) {
    $regex = "/\A(?:.*?[\w\"'][.?!](?=['\"]?\s|\$)){0,{$x}}/ms";
    if (preg_match($regex, $text, $matches)) return $matches[0];
    return ''; // Never get here (will always match).
}

Вот прокомментированная версия регулярного выражения:

$regex = '/# Match first $x sentences, each ending in [.?!]
    \A                # Anchor to beginning of string
    (?:               # Non-capture group to apply count
      .*?             # Lazily match zero or more characters.
      [\w"\']         # Last char before end is word or quote.
      [.?!]           # End of sentence puntuation [.?!]
      (?=[\'"]?\s|$)  # But only if followed by space or EOL
    ){0,5}            # Match from zero to $x sentences.
    /smx';

Обратите внимание, что это также обрабатывает предложения, которые заканчиваются кавычками, например "This one." или "This one!" или 'This one'?

0 голосов
/ 29 марта 2011

Регулярное выражение заканчивается безусловным совпадением пробельного символа. Если во входных данных содержится ровно 5 предложений, и после последнего периода пробелов нет, первое совпадет, а второе - нет.

...