Как я могу посчитать количество слов между двумя словами? - PullRequest
1 голос
/ 21 июля 2010

Как я могу посчитать количество слов между двумя словами?

   $txt = "tükörfúrógép banana orange lime, tükörfúrógép cherry árvíztűrő orange lyon
    cat lime mac tükörfúrógép cat orange lime cat árvíztűrő
    tükörfúrógép banana orange lime
    orange lime cat árvíztűrő";

Два слова: 'árvíztűrő' и 'tükörfúrógép'
Мне нужно это возвращение:
tükörfúrógép cherry árvíztűrő
tükörfúrógép cat оранжевый лайм кошка árvíztőr0
tükörfúrógép банан, апельсин, лайм оранжевый лайм кот árvíztűrő

Теперь у меня есть это регулярное выражение:

preg_match_all('@((tükörfúrógép(.*)?árvíztűrő)(árvíztűrő(.*)?tükörfúrógép))@sui',$txt,$m);

Ответы [ 3 ]

7 голосов
/ 21 июля 2010

У меня есть несколько вещей, на которые нужно указать:

  1. Вы не можете сделать это за одно регулярное выражение.Регулярное выражение только вперед, для обратного порядка матчей требуется второе регулярное выражение.
  2. Вы используете (.*)?, но вы имеете в виду (.*?)
  3. Чтобы получить правильные совпадения, выдолжен гарантировать, что левая граница вашего выражения не может быть посередине.
  4. Вы должны обозначать границы слов (\b) вокруг слов-разделителей, чтобы обеспечить совпадение целых слов. РЕДАКТИРОВАТЬ: Хотя это правильно в теории, это не работает для ввода Unicode в PHP.
  5. Вы должны переключить язык PHP на венгерский (это это Венгерский, верно?) перед вызовом preg_match_all(), потому что локаль влияет на то, что в PHP считается границей слова. РЕДАКТИРОВАТЬ: значение \b на самом деле не меняет с выбранным языком.

При этом, регулярное выражение # 1:

(\btükörfúrógép\b)((?:(?!\1).)*?)\bárvíztűrő\b

и регулярное выражение # 2 аналогично, только с обратными словами-разделителями.

Regex объяснение:

(               # match group 1:
  \b            #   a word boundary
  tükörfúrógép  #   your first delimiter word
  \b            #   a word boundary
)               # end match group 1
(               # match group 2:
  (?:           #   non-capturing group:
    (?!         #     look-ahead:
      \1        #       must not be followed by delimiter word 1
    )           #     end look-ahead
    .           #     match any next char (includes \n with the "s" switch)
  )*?           #   end non-capturing group, repeat as often as necessary
)               # end match group 2 (this is the one you look for)
\b              # a word boundary
árvíztűrő       # your second delimiter word
\b              # a word boundary

ОБНОВЛЕНИЕ: С патетическая плохая поддержка строк Unicode в PHP, вы будете вынуждены использовать подобные выражения в качестве замены для \b:

$before = '(?<=^|[^\p{L}])';
$after  = '(?=[^\p{L}]|$)';

Это предложение взято из другого вопроса .

3 голосов
/ 21 июля 2010

Для подсчета слов между двумя словами вы можете легко использовать:

count(split(" ", "lime orange banana"));

И функция , которая возвращает массив с совпадениями и счетами, будетбыть:

<code>function count_between_words($text, $first, $second, $case_sensitive = false)
{
    if(!preg_match_all('/('.$first.')((?:(?!\\1).)*?)'.$second.'/s' . ($case_sensitive ? "" : "i"), preg_replace("/\\s+/", " ", $text), $results, PREG_SET_ORDER))
        return array();

    $data = array();

    foreach($results as $result)
    {
        $result[2] = trim($result[2]);
        $data[] = array("match" => $result[0], "words" => $result[2], "count" => count(split(" ", $result[2])));
    }

    return $data;
}

$result = count_between_words($txt, "tükörfúrógép", "árvíztűrő");

echo "<pre>" . print_r($result, true) . "
";

Результат будет:

Array
(
    [0] => Array
    (
        [match] => tükörfúrógép cherry árvíztűrő
        [words] => cherry
        [count] => 1
    )

    [1] => Array
    (
        [match] => tükörfúrógép cat orange lime cat árvíztűrő
        [words] => cat orange lime cat
        [count] => 4
    )

    [2] => Array
    (
        [match] => tükörfúrógép banana orange lime orange lime cat árvíztűrő
        [words] => banana orange lime orange lime cat
        [count] => 6
    )
)
1 голос
/ 21 июля 2010

Вместо огромного, запутанного регулярного выражения, почему бы не написать несколько строк, используя различные строковые функции?

Пример:

$start = strpos($txt, 'árvíztűrő') + 9; // position of first char after 'árvíztűrő'
$end   = strpos($txt, 'tükörfúrógép', $start);
$inner = substr($txt, $start, $end - $start);
$words = preg_split("/[\s,]+/", $inner);
$num   = count($words);

Конечно, это израсходует память, если у вас есть какая-то гигантская строка ввода ...

...