Я хочу разобрать короткий код, например WordPress с атрибутами:
Входные данные:
[include file="header.html"]
Мне нужен вывод как массив, имя функции «include» и атрибуты со значениями, любая помощь будет оценена.
благодаря
Используя эту функцию
$code = '[include file="header.html"]'; $innerCode = GetBetween($code, '[', ']'); $innerCodeParts = explode(' ', $innerCode); $command = $innerCodeParts[0]; $attributeAndValue = $innerCodeParts[1]; $attributeParts = explode('=', $attributeParts); $attribute = $attributeParts[0]; $attributeValue = str_replace('\"', '', $attributeParts[1]); echo $command . ' ' . $attribute . '=' . $attributeValue; //this will result in include file=header.html
$ command будет включать "включить"
$ attribute будет "file"
$ attributeValue будет "header.html"
Вот класс утилиты, который мы использовали в нашем проекте. Он будет соответствовать всем коротким кодам в строке (включая html), и он выведет ассоциативный массив, включающий их name
, attributes
и content
final class Parser { // Regex101 reference: https://regex101.com/r/pJ7lO1 const SHORTOCODE_REGEXP = "/(?P<shortcode>(?:(?:\\s?\\[))(?P<name>[\\w\\-]{3,})(?:\\s(?P<attrs>[\\w\\d,\\s=\\\"\\'\\-\\+\\#\\%\\!\\~\\`\\&\\.\\s\\:\\/\\?\\|]+))?(?:\\])(?:(?P<content>[\\w\\d\\,\\!\\@\\#\\$\\%\\^\\&\\*\\(\\\\)\\s\\=\\\"\\'\\-\\+\\&\\.\\s\\:\\/\\?\\|\\<\\>]+)(?:\\[\\/[\\w\\-\\_]+\\]))?)/u"; // Regex101 reference: https://regex101.com/r/sZ7wP0 const ATTRIBUTE_REGEXP = "/(?<name>\\S+)=[\"']?(?P<value>(?:.(?![\"']?\\s+(?:\\S+)=|[>\"']))+.)[\"']?/u"; public static function parse_shortcodes($text) { preg_match_all(self::SHORTOCODE_REGEXP, $text, $matches, PREG_SET_ORDER); $shortcodes = array(); foreach ($matches as $i => $value) { $shortcodes[$i]['shortcode'] = $value['shortcode']; $shortcodes[$i]['name'] = $value['name']; if (isset($value['attrs'])) { $attrs = self::parse_attrs($value['attrs']); $shortcodes[$i]['attrs'] = $attrs; } if (isset($value['content'])) { $shortcodes[$i]['content'] = $value['content']; } } return $shortcodes; } private static function parse_attrs($attrs) { preg_match_all(self::ATTRIBUTE_REGEXP, $attrs, $matches, PREG_SET_ORDER); $attributes = array(); foreach ($matches as $i => $value) { $key = $value['name']; $attributes[$i][$key] = $value['value']; } return $attributes; } } print_r(Parser::parse_shortcodes('[include file="header.html"]'));
Вывод:
Array ( [0] => Array ( [shortcode] => [include file="header.html"] [name] => include [attrs] => Array ( [0] => Array ( [file] => header.html ) ) ) )
Мне также нужна эта функциональность в моей PHP-среде. Это то, что я написал, он работает очень хорошо. Он работает с анонимными функциями, которые мне очень нравятся (это немного напоминает функции обратного вызова в JavaScript).
<?php //The content which should be parsed $content = '<p>Hello, my name is John an my age is [calc-age day="4" month="10" year="1991"].</p>'; $content .= '<p>Hello, my name is Carol an my age is [calc-age day="26" month="11" year="1996"].</p>'; //The array with all the shortcode handlers. This is just a regular associative array with anonymous functions as values. A very cool new feature in PHP, just like callbacks in JavaScript or delegates in C#. $shortcodes = array( "calc-age" => function($data){ $content = ""; //Calculate the age if(isset($data["day"], $data["month"], $data["year"])){ $age = date("Y") - $data["year"]; if(date("m") < $data["month"]){ $age--; } if(date("m") == $data["month"] && date("d") < $data["day"]){ $age--; } $content = $age; } return $content; } ); //http://stackoverflow.com/questions/18196159/regex-extract-variables-from-shortcode function handleShortcodes($content, $shortcodes){ //Loop through all shortcodes foreach($shortcodes as $key => $function){ $dat = array(); preg_match_all("/\[".$key." (.+?)\]/", $content, $dat); if(count($dat) > 0 && $dat[0] != array() && isset($dat[1])){ $i = 0; $actual_string = $dat[0]; foreach($dat[1] as $temp){ $temp = explode(" ", $temp); $params = array(); foreach ($temp as $d){ list($opt, $val) = explode("=", $d); $params[$opt] = trim($val, '"'); } $content = str_replace($actual_string[$i], $function($params), $content); $i++; } } } return $content; } echo handleShortcodes($content, $shortcodes); ?>
Результат:
Привет, меня зовут Джон, мой возраст – 22 года.
Привет, меня зовут Кэрол, мой возраст – 17 лет.
Это на самом деле сложнее, чем может показаться на поверхности. Ответ Эндрю работает, но начинает разрушаться, если в исходном тексте появляются квадратные скобки [например, это]. WordPress работает, предварительно зарегистрировав список действительных коротких кодов и только действуя на текст внутри скобок, если он соответствует одному из этих предопределенных значений. Таким образом, он не калечит какой-либо обычный текст, который мог бы иметь в своем распоряжении набор квадратных скобок.
Фактический исходный код движка короткого кода WordPress достаточно прочен, и не похоже, что было бы очень сложно изменить файл для запуска сам по себе, – тогда вы можете использовать его в своем приложении для обработки жесткой работы. (Если вам интересно, посмотрите на get_shortcode_regex()
в этом файле, чтобы увидеть, насколько волосатым может быть правильное решение этой проблемы.)
Очень грубая реализация вашего вопроса с использованием WP shortcodes.php будет выглядеть примерно так:
// Define the shortcode function inlude_shortcode_func($attrs) { $data = shortcode_atts(array( 'file' => 'default' ), $attrs); return "Including File: {$data['file']}"; } add_shortcode('include', 'inlude_shortcode_func'); // And then run your page content through the filter echo do_shortcode('This is a document with [include file="header.html"] included!');
Опять же, не тестировалось вообще, но это не очень жесткий API для использования.