Токен соответствия и его контекст с возможным перекрытием - PullRequest
1 голос
/ 23 сентября 2019

Я обрабатываю некоторые текстовые файлы и хочу найти определенные токены, а также часть текста, окружающего их, чтобы получить некоторый контекст.Моя проблема в том, что я не могу найти каждый экземпляр токенов, если они достаточно близки, чтобы быть захваченным контекстом токена, предшествующего ему.

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

Сначала я попробовал что-то вроде:

<?php
$text = "Lorem ipsum 11111 dolor sit 22222 amet, consectetur 33333 adipiscing elit, sed do eiusmod tempor 1111 incididunt ut 11111 labore et dolore magna aliqua.";
$nmbrs_tmp = array();
preg_match_all("@.{0,19}[^\d](\d{5})[^\d].{0,19}@s", $text, $nmbrs_tmp);
print_r($nmbrs_tmp);

Но он не захватит 22222потому что он уже находится в первом захвате 11111 и его контекст:

//output
Array
(
    [0] => Array
        (
            [0] => Lorem ipsum 11111 dolor sit 22222 ame
            [1] => t, consectetur 33333 adipiscing elit, se
            [2] =>  1111 incididunt ut 11111 labore et dolore ma
        )

    [1] => Array
        (
            [0] => 11111
            [1] => 33333
            [2] => 11111
        )

)

Затем я попытался использовать lookaheads и lookbehinds, но 1st: lookbehinds должен быть фиксированной длины, а 2nd: я больше не буду захватывать контекст:"@(?<=.{0,19})[^\d](\d{5})[^\d](?=.{0,19})@s" //this won't work

В идеале мне бы понравилось что-то подобное, где я фиксирую каждый экземпляр 5-значных чисел, а также получаю всевозможный контекст:

//output
Array
(
    [0] => Array
        (
            [0] => Lorem ipsum 11111 dolor sit 22222 ame
            [1] => sum 11111 dolor sit 22222 amet, consectetur 3
            [2] => 2 amet, consectetur 33333 adipiscing elit, se
            [3] =>  1111 incididunt ut 11111 labore et dolore ma
        )

    [1] => Array
        (
            [0] => 11111
            [1] => 22222
            [2] => 33333
            [3] => 11111
        )

)

Если просто нет возможностичтобы сделать это с помощью регулярного выражения, тогда я открыт для решений PHP, которые предполагают многократный просмотр текста или использование большего количества регулярных выражений.

1 Ответ

0 голосов
/ 23 сентября 2019

Вот метод, использующий смещения совпадения для вычисления соответствующих подстрок:

<?php
$text = "99999 Lorem ipsum 11111 dolor sit 22222 amet, consectetur 33333 adipiscing elit, sed do eiusmod tempor 1111 incididunt ut 11111 labore et dolore magna aliqua. 99999";
$nmbrs_tmp = array();
preg_match_all("@\b\d{5}\b@s", $text, $nmbrs_tmp, PREG_OFFSET_CAPTURE);

foreach ($nmbrs_tmp[0] as $key => $field) {
    $offset = $field[1];
    $start = ( $offset>=20 ? $offset-20 : 0 );
    $length = $offset>=20 ? 45 : 45-(20-$offset);
    $nmbrs_tmp[0][$key][2] = substr( $text, $start, $length );
}

print_r($nmbrs_tmp);

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

Затем мы сопоставляем, передавая флаг PREG_OFFSET_CAPTURE.

Наконец, мы используем возвращенное смещение, чтобы вычислить длину нужной подстроки (вероятно, не имеет значения, падает ли $length)от конца входа, но вы можете отрегулировать его, если хотите).

Результат:

Array
(
    [0] => Array
        (
            [0] => Array
                (
                    [0] => 99999
                    [1] => 0
                    [2] => 99999 Lorem ipsum 11111 d
                )

            [1] => Array
                (
                    [0] => 11111
                    [1] => 18
                    [2] => 99999 Lorem ipsum 11111 dolor sit 22222 ame
                )

            [2] => Array
                (
                    [0] => 22222
                    [1] => 34
                    [2] => sum 11111 dolor sit 22222 amet, consectetur 3
                )

            [3] => Array
                (
                    [0] => 33333
                    [1] => 58
                    [2] => 2 amet, consectetur 33333 adipiscing elit, se
                )

            [4] => Array
                (
                    [0] => 11111
                    [1] => 122
                    [2] =>  1111 incididunt ut 11111 labore et dolore ma
                )

            [5] => Array
                (
                    [0] => 99999
                    [1] => 159
                    [2] => olore magna aliqua. 99999
                )

        )

)
...