PHP preg_split использует разделитель в качестве ключей массива - PullRequest
0 голосов
/ 18 сентября 2018

Мне нужно разделить строку разделителем регулярных выражений, но нужен разделитель в качестве ключа массива.

Вот пример строки:

*01the title*35the author*A7other useless infos*AEother useful infos*AEsome delimiters can be there multiple times

Разделителем является звездочка (*), за которыми следуют два буквенно-цифровых символа.Я использую этот шаблон регулярных выражений: /\*[A-Z0-9]{2}/

Это мой вызов preg_split:

$attributes = preg_split('/\*[A-Z0-9]{2}/', $line);

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

То, что я получаю, выглядит так:

$matches = [
        0 => 'the title',
        1 => 'the author',
        2 => 'other useless infos',
        3 => 'other useful infos',
        4 => 'some delimiters can be there multiple times'
    ];

Это должно выглядеть так:

$matches = [
        '*01' => 'the title',
        '*35' => 'the author',
        '*A7' => 'other useless infos',
        '*AE' => [
            'other useful infos',
            'some delimiters can be there multiple times',
        ],
    ];

Кто-нибудь есть какие-либо предложения о том, как этого добиться?

Ответы [ 3 ]

0 голосов
/ 18 сентября 2018

Вы можете сопоставить и записать ключи в группу 1 и весь текст до следующего разделителя в группу 2, где разделитель не совпадает с первым полученным разделителем.Затем, в цикле, проверьте все ключи и значения и разделите эти значения с помощью шаблона разделителя, где он появляется один или несколько раз.

Регулярное выражение равно

(\*[A-Z0-9]{2})(.*?)(?=(?!\1)\*[A-Z0-9]{2}|$)

См. regex demo .

Подробности

  • (\*[A-Z0-9]{2}) - Разделитель, группа 1: a * и две заглавные буквы или цифры
  • (.*?) - значение, группа 2: любые 0+ символов, кроме символов разрыва строки, как можно меньше
  • (?=(?!\1)\*[A-Z0-9]{2}|$) - до шаблона разделителя (\*[A-Z0-9]{2}), который не являетсясоответствует тексту, захваченному в группе 1 ((?!\1)) или концу строки ($).

См. демонстрационную версию PHP :

$re = '/(\*[A-Z0-9]{2})(.*?)(?=(?!\1)\*[A-Z0-9]{2}|$)/';
$str = '*01the title*35the author*A7other useless infos*AEother useful infos*AEsome delimiters can be there multiple times';
$res = [];
if (preg_match_all($re, $str, $m, PREG_SET_ORDER, 0)) {
    foreach ($m as $kvp) {
        $tmp = preg_split('~\*[A-Z0-9]+~', $kvp[2]);
        if (count($tmp) > 1) {
            $res[$kvp[1]] = $tmp;
        } else {
            $res[$kvp[1]] = $kvp[2];
        }
    }
    print_r($res);
}

Вывод:

Array
(
    [*01] => the title
    [*35] => the author
    [*A7] => other useless infos
    [*AE] => Array
        (
            [0] => other useful infos
            [1] => some delimiters can be there multiple times
        )

)
0 голосов
/ 18 сентября 2018

Хорошо, я отвечаю на свой вопрос о том, как обрабатывать несколько одинаковых разделителей.Спасибо @ markus-ankenbrand за начало:

$attributes = preg_split('/(\*[A-Z0-9]{2})/', $line, -1, PREG_SPLIT_DELIM_CAPTURE);
        $matches = [];
        for ($i = 1; $i < sizeof($attributes) - 1; $i += 2) {
            if (isset($matches[$attributes[$i]]) && is_array($matches[$attributes[$i]])) {
                $matches[$attributes[$i]][] = $attributes[$i + 1];
            } elseif (isset($matches[$attributes[$i]]) && !is_array($matches[$attributes[$i]])) {
                $currentValue = $matches[$attributes[$i]];
                $matches[$attributes[$i]] = [$currentValue];
                $matches[$attributes[$i]][] = $attributes[$i + 1];
            } else {
                $matches[$attributes[$i]] = $attributes[$i + 1];
            }
        }

Толстый оператор if / else выглядит не очень красиво, но он делает то, что должен.

0 голосов
/ 18 сентября 2018

Используйте флаг PREG_SPLIT_DELIM_CAPTURE функции preg_split, чтобы также получить захваченный разделитель (см. документация ).

Так в вашем случае:

# The -1 is the limit parameter (no limit)
$attributes = preg_split('/(\*[A-Z0-9]{2})/', $line, -1, PREG_SPLIT_DELIM_CAPTURE);

Теперь у вас есть элемент 0 из $attributes как все перед первым разделителем, а затем чередующийся захваченный разделитель и следующая группа, чтобы вы могли построить свой массив $matches следующим образом (при условии, что вы не хотите сохранятьпервая группа):

for($i=1; $i<sizeof($attributes)-1; $i+=2){
    $matches[$attributes[$i]] = $attributes[$i+1];
}

Чтобы учесть наличие разделителей несколько раз, можно настроить строку внутри цикла for, чтобы проверить, существует ли этот ключ, и в этом случае создать массив.

Редактировать: возможность создания массива, если необходимо, заключается в использовании этого кода:

for($i=1; $i<sizeof($attributes)-1; $i+=2){
    $key = $attributes[$i];
    if(array_key_exists($key, $matches)){
        if(!is_array($matches[$key]){
            $matches[$key] = [$matches[$key]];
        }
        array_push($matches[$key], $attributes[$i+1]);
    } else {
        $matches[$attributes[$i]] = $attributes[$i+1];
    }
}

Код вниз по потоку, безусловно, может быть упрощен, особенно если вы помещаете все значения в (возможно, в один элемент) массивы.

...