Shadow
Shadow

Reputation: 141

Regex of shortcode in Php

I don't know what the title of the question should be. This something logical and what I lack is the same.

I have a string in the format [CONST att1="value1" att2="value2"] and created a regex that was working fine. But certain conditions made this regex wrong.

$data = preg_split('/(?<=\")\s/', $replace_str[1]);
foreach ($data as $index_val => $exp_data) {
    if(!empty($exp_data)){
        $attributes = explode('=',$exp_data);
        if(count($attributes) > 0){
            $index = strtolower(str_replace(array("'", "\""), "", trim($attributes[0])));
            $item_value = str_replace(array("'", "\""), "", trim($attributes[1]));
            $item_value = $attributes[1];
            $array_data[$index] = $item_value;
        }
    }
}

Then using the array to get key value. But in some instance, say if the format is like the one below

[CONST att1="value1" att2= "value2"]

the exploded variable contains "value2" (notice the prefixed space). What i want is "value2".

So since my format is similar to that of WordPress shortcode referred shortcode.php file in WordPress and found @[<>&/\[\]\x00-\x20=]@ inside the file. But I am unable to understand or make it work.

I need to access value1 and value2 as clean data. i.e, without spaces, single and double quotes at the start and end. Also if the order of the att1 and att2 is changed, it should work.

[CONST att2="value2" att1="value1"]

Should output:

array(att1=>value1,att2=>value2)

Upvotes: 1

Views: 598

Answers (1)

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626920

I suggest collecting keys and values in the shortcode string using a matching regex with preg_match_all like

'~(?:\G(?!\A)\s+|^\[\w+\s+)\K([^\s=]*)\s*=\s*"([^"]*)"~'

See the regex demo.

Details

  • (?:\G(?!\A)\s+|^\[\w+\s+)
  • \K - match reset operator
  • ([^\s=]*) - Group 1 (attribute name): 0+ chars other than whitespace and =
  • \s*=\s* - a = enclosed with 0+ whitespaces
  • " - a double quotation mark
  • ([^"]*) - Group 2 (attribute value inside quotes): any 0+ chars other than "
  • " - a double quotation mark

After you get an array of matches you will have to build your associative array "manually" like

$s = '[CONST att1="value1" att2="value2"]';
preg_match_all('/(?:\G(?!\A)\s+|^\[\w+\s+)\K(\w+)\s*=\s*"([^"]*)"/', $s, $array_data, PREG_SET_ORDER, 0);
$res = [];
foreach ($array_data as $kvp) {
    $res[$kvp[1]] =  $kvp[2];
}
print_r($res);
// -> Array ( [att1] => value1 [att2] => value2 )

See the PHP demo.

Another way of processing the matches (demo):

if (preg_match_all('/(?:\G(?!\A)\s+|^\[\w+\s+)\K(\w+)\s*=\s*"([^"]*)"/', $s, $array_data)) {
    array_shift($array_data);
    print_r(array_combine($array_data[0], $array_data[1]));
}

Upvotes: 1

Related Questions