Регулярное выражение для анализа пользовательских подстрок шорткода в статье и генерации массива

#php #regex

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

Вопрос:

Мне может понадобиться небольшая помощь с этим регулярным выражением. Приведенное ниже регулярное выражение работает.

 $regexgameid = '/{gameids([0-9][0-9][0-9][0-9][0-9])|([0-9][0-9][0-9][0-9][0-9])|([0-9][0-9][0-9][0-9][0-9])}/i';
preg_match_all($regexgameid, $articletext, $matchesgameid, PREG_SET_ORDER);
  

Пример целевого шорткода: {gameid 45735 76352 87262}

Количество идентификаторов игры может быть одним или тремя.

С моей логикой это было бы так:

 $regexgameid = '/{gameids([0-9]{5}){1,3}}/i';
preg_match_all($regexgameid, $articletext, $matchesgameid, PREG_SET_ORDER);
  

Но это регулярное выражение выше не работает.


Чего я пытаюсь добиться, так это получить результаты из preg_match_all() структуры массива, подобной этой:

 Array
(
    [0] => {gameid
    [1] => 45735
    [2] => 76352
    [3] => 87262
    [4] => }
)
  

чтобы я мог заменить весь {gameid 45735 76352 87262} шорткод в тексте статьи информацией о 3 идентификаторах игр.

Комментарии:

1. Ваше регулярное выражение не допускает пробелов между числами. {gameids([0-9]{5}s?){1,3}} возможно

2. Как насчет: (?<game>gameid(?:.d{5}){1,3}) ?

Ответ №1:

Вот демонстрация того, как использовать preg_replace_callback() для замены тегов шорткода gameid в ваших (я полагаю, Joomla) статьях.

В своем вопросе вы указываете, что количество идентификаторов игры будет либо одним, либо тремя. По этой причине вам не следует использовать синтаксис {1,3} квантора, потому что это означает «от одного до трех» вместо «один или три». Другими словами, для правильного шаблона потребуется, чтобы второй и третий идентификаторы существовали оба или ни один.

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

Код: (Демо)

 $articleText = <<<TEXT
Some article text
Triple id: {gameid 45735 76352 87262}.
Do not honor {gameid 12345 67890} because contains exactly 2 game ids!
unknown id: {gameid 66666} can't replace it!
Found single id: {gameid 76352}
finished the article
TEXT;

$gamesLookup = [
    45735 => 'Pac-man',
    76352 => 'Donkey Kong',
    87262 => 'Rampage'
];

echo preg_replace_callback(
    '~{gameid (d{5})(?: (d{5}) (d{5}))?}~',
    function ($m) use ($gamesLookup) {
        echo 'm = ' . var_export($m, true) . "n---n";
        return 'Game Name(s): ' . strtr(implode(', ', array_slice($m, 1)), $gamesLookup);
    },
    $articleText
);
  

Вывод: (Я распечатываю массивы совпадений, чтобы вы могли видеть данные, к которым вам потребуется доступ)

 m = array (
  0 => '{gameid 45735 76352 87262}',
  1 => '45735',
  2 => '76352',
  3 => '87262',
)
---
m = array (
  0 => '{gameid 66666}',
  1 => '66666',
)
---
m = array (
  0 => '{gameid 76352}',
  1 => '76352',
)
---
Some article text
Triple id: Game Name(s): Pac-man, Donkey Kong, Rampage.
Do not honor {gameid 12345 67890} because contains exactly 2 game ids!
unknown id: Game Name(s): 66666 can't replace it!
Found single id: Game Name(s): Donkey Kong
finished the article
  

Если вам просто нужен preg_match_all() вызов, то достаточно того же шаблона…

Код: (Демо)

 var_export(
    preg_match_all('~{gameid (d{5})(?: (d{5}) (d{5}))?}~', $articleText, $m, PREG_SET_ORDER)
    ? $m
    : []
);
  

Ответ №2:

Здесь есть несколько проблем. Во-первых, ваше исходное регулярное выражение неправильно использовало чередование: this (сокращено для краткости)…

 /{gameids([0-9])|([0-9])}/
  

… на самом деле совпадает либо с on {gameid 5} , либо только с on 5 , но никогда со всей группой. Скорее всего, это не то, что вы хотели.

Во-вторых, как правильно заметил @NigelRen, в вашем примере между последовательностью цифр есть пробел, но новый шаблон его не покрывает.

Вот один из подходов (предполагая, что вам действительно нужны целые идентификаторы игр, а не только цифры, сохраненные в $matchesgameid ):

 $articletext = 'Here is some {gameid 55555 44444 33333} and here is some more {gameid 55555} and this is one more time {gameid 55555 33333}';
$regexgameid = '/{gameid(?:s[0-9]{5}){1,3}}/i';
preg_match_all($regexgameid, $articletext, $matchesgameid, PREG_SET_ORDER);
  

ДЕМОНСТРАЦИЯ. Группа переноса цифр здесь не фиксируется — как для экономии производительности, так и для того, чтобы не отвлекаться на результаты. Если идентификаторы GameID имеют противоречивые пробелы (у некоторых есть внутри, у некоторых нет), просто отметьте s как необязательный с ? помощью квантора:

 '/{gameid(?:s?[0-9]{5}){1,3}}/i';