11

我想用属性解析像 Wordpress 这样的短代码:

输入:

[include file="header.html"]

我需要输出为数组,函数名称“包含”和带有值的属性,任何帮助将不胜感激。

谢谢

4

7 回答 7

8

这是我们在项目中使用的实用程序类,它将匹配字符串中的所有短代码(包括 html),并将输出一个关联数组,包括它们的name,attributescontent

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
                        )
                )
        )
)
于 2015-09-11T13:54:17.147 回答
4

使用此功能

$code = '[include file="header.html"]';
$innerCode = GetBetween($code, '[', ']');
$innerCodeParts = explode(' ', $innerCode);

$command = $innerCodeParts[0];

$attributeAndValue = $innerCodeParts[1];
$attributeParts = explode('=', $attributeAndValue);
$attribute = $attributeParts[0];
$attributeValue = str_replace('"', '', $attributeParts[1]);

echo $command . ' ' . $attribute . '=' . $attributeValue;
//this will result in include file=header.html

$command 将是“包括”

$attribute 将是“文件”

$attributeValue 将是“header.html”

于 2013-03-31T22:33:48.967 回答
3

我的 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);
?>

结果:
您好,我的名字是 John,我的年龄是 22。
您好,我的名字是 Carol,我的年龄是 17。

于 2014-10-03T21:30:32.380 回答
1

这实际上比表面上看起来更难。安德鲁的答案有效,但如果方括号出现在源文本中[例如,像这样],就会开始崩溃。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。

于 2013-03-31T23:49:14.840 回答
0

更新@Duco 的片段,看起来,当我们有一些类似的东西时,它会被空间破坏

[Image source="myimage.jpg" alt="My Image"]

对当前的一个:

function handleShortcodes($content, $shortcodes){
    function read_attr($attr) {
        $atList = [];

        if (preg_match_all('/\s*(?:([a-z0-9-]+)\s*=\s*"([^"]*)")|(?:\s+([a-z0-9-]+)(?=\s*|>|\s+[a..z0-9]+))/i', $attr, $m)) {
            for ($i = 0; $i < count($m[0]); $i++) {
                if ($m[3][$i])
                    $atList[$m[3][$i]] = null;
                else
                    $atList[$m[1][$i]] = $m[2][$i];
            }
        }
        return $atList;
    }
    //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){
                $params = read_attr($temp);
                $content = str_replace($actual_string[$i], $function($params), $content);
                $i++;
            }
        }
    }
    return $content;
}
$content = '[image source="one" alt="one two"]';

结果:

array( 
  [source] => myimage.jpg,
  [alt] => My Image
)

更新(2020 年 2 月 11 日)
它似乎在 preg_match 下遵循正则表达式,仅标识具有属性的短代码

preg_match_all("/\[".$key." (.+?)\]/", $content, $dat);

使其正常工作[contact-form][mynotes]。我们可以将以下内容更改为

preg_match_all("/\[".$key."(.*?)\]/", $content, $dat);
于 2019-12-09T04:01:27.933 回答
0

我用wordpress函数修改了上面的函数

function extractThis($short_code_string) {
    $shortocode_regexp = "/(?P<shortcode>(?:(?:\\s?\\[))(?P<name>[\\w\\-]{3,})(?:\\s(?P<attrs>[\\w\\d,\\s=\\\"\\'\\-\\+\\#\\%\\!\\~\\`\\&\\.\\s\\:\\/\\?\\|]+))?(?:\\])(?:(?P<content>[\\w\\d\\,\\!\\@\\#\\$\\%\\^\\&\\*\\(\\\\)\\s\\=\\\"\\'\\-\\+\\&\\.\\s\\:\\/\\?\\|\\<\\>]+)(?:\\[\\/[\\w\\-\\_]+\\]))?)/u";
    preg_match_all($shortocode_regexp, $short_code_string, $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 = shortcode_parse_atts($value['attrs']);
        $shortcodes[$i]['attrs'] = $attrs;
       }
       if (isset($value['content'])) {
        $shortcodes[$i]['content'] = $value['content'];
       }
    }
    return $shortcodes;
  }

我认为这对所有人都有帮助:)

于 2020-01-22T10:41:10.617 回答
0

我只是有同样的问题。对于我必须做的事情,我将利用现有的 xml 解析器,而不是编写自己的正则表达式。我确信在某些情况下它不起作用

例子.php

<?php

$file_content = '[include file="header.html"]';

// convert the string into xml
$xml = str_replace("[", "<", str_replace("]", "/>", $file_content));

$doc = new SimpleXMLElement($xml);

echo "name: " . $doc->getName() . "\n";
foreach($doc->attributes() as $key => $value) {
    echo "$key: $value\n";
}
$ php example.php 
name: include
file: header.html

为了让它在 ubuntu 上运行,我认为你必须这样做

sudo apt-get install php-xml

(感谢https://drupal.stackexchange.com/a/218271

如果文件中有很多这些字符串,那么我认为您仍然可以进行查找替换,然后将其全部视为 xml。

于 2021-11-01T16:49:15.280 回答