WordPress: проблема с регулярным выражением shortcode

Это регулярное выражение, используемое для «коротких кодов» в WordPress (одно для всего тега, другое для атрибутов).

return '(.?)\[('.$tagregexp.')\b(.*?)(?:(\/))?\](?:(.+?)\[\/\2\])?(.?)'; $pattern = '/(\w+)\s*=\s*"([^"]*)"(?:\s|$)|(\w+)\s*=\s*\'([^\']*)\'(?:\s|$)|(\w+)\s*=\s*([^\s\'"]+)(?:\s|$)|"([^"]*)"(?:\s|$)|(\S+)(?:\s|$)/'; 

Он разбирает такие вещи, как

 [foo bar="baz"]content[/foo] 

или

 [foo /] 

В Trap WordPress они говорят, что это немного некорректно, но моя главная проблема заключается в том, что он не поддерживает короткие коды внутри атрибутов, например, в

 [foo bar="[baz /]"]content[/foo] 

потому что регулярное выражение останавливает основной код короткого замыкания при первом появлении закрывающей скобки, поэтому в примере он отображает

 [foo bar="[baz /] 

а также

 "]content[/foo] 

показывает, как есть.

Есть ли способ изменить регулярное выражение, чтобы он обходил любое появление [ с ] и его содержимое, когда происходит между открывающим тегом или самозакрывающимся тегом?

Какова ваша цель? Даже если регулярное выражение WordPress было лучше, короткий код не был бы выполнен.

 return '(.?)\[('.$tagregexp.')\b((?:"[^"]*"|.)*?)(?:/)?\](?:(.+?)\[\/\2\])?(.?)'; 

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

 (?:"[^"]*"|.)*? 

вместо

 .*? 

Обратите внимание, что он не обрабатывает строки с экранированными символами кавычек в них (все же – может быть сделано, но это необходимо?). Я ничего не изменил, потому что не знаю синтаксиса для коротких кодов WordPress.

Но похоже, что его можно было немного очистить, удалив ненужные обратные косые черты и круглые скобки:

 return '(.?)\[(foo)\b((?:"[^"]*"|.)*?)/?\](?:(.+?)\[/\2\])?(.?)'; 

Возможно, необходимы дальнейшие улучшения. Меня немного беспокоит нечеткая точка в приведенном выше фрагменте, и я предпочел бы использовать (?:"[^"]*"|[^/\]])* Вместо (?:"[^"]*"|.)*? , но я не знаю, нарушит ли это что-то другое. Кроме того, я не знаю, для чего подходят ведущие и конечные (.?) . Они не соответствуют чему-либо в вашем примере, поэтому я не знаю их цели.

Вы хотите замену замены для этого регулярного выражения? Это позволяет значениям атрибутов содержать те вещи, которые выглядят как теги, как в вашем примере:

 '(.?)\[(\w+)\b((?:[^"\'\[\]]++|(?:"[^"]*+")|(?:\'[^\']*+\'))*+)\](?:(?<=(\/)\])|([^\[\]]*+)\[\/\2\])(.?)' 

Или в более удобочитаемой форме:

 /(.?) # could be [ \[(\w+)\b # tag name ((?:[^"'\[\]]++ # attributes |(?:"[^"]*+") |(?:'[^']*+') )*+ )\] (?:(?<=(\/)\]) # '/' if self-closing |([^\[\]]*+) # ...or content \[\/\2\] # ...and closing tag )(.?) # could be ] / 

Как я понимаю, $tagregexp в оригинале является чередованием всех $tagregexp тегов, которые были определены; Я заменил \w+ на читаемость. Все исходное регулярное выражение захватывает, это тоже делает и в тех же группах. Единственное различие заключается в том, что / в самозакрывающемся теге захватывается в группе # 3 вместе с атрибутами, а также в своей собственной группе (# 4).

Я не думаю, что другое регулярное выражение нужно изменить, если вы не захотите добавить полную поддержку тегов, встроенных в значения атрибутов. Это также означало бы использование скрытых кавычек в этом, и я не знаю, как вы хотели бы это сделать. Удвоение их было бы моей догадкой; вот как это делает Textpattern, и WordPress предположительно основывается на этом.

Этот вопрос является хорошим примером того, почему приложения, такие как WordPress, не должны быть реализованы с помощью регулярных выражений. Единственный способ добавить или изменить функциональность – сделать регулярные выражения более крупными и уродливыми и еще сложнее поддерживать.

Я нашел способ исправить это: во-первых, измените регулярное выражение для короткого кода:

 (.?)\[('.$tagregexp.')\b(.*?)(?:(\/))?\](?:(.+?)\[\/\2\])?(.?) 

Для того, чтобы:

 (.?)\[('.$tagregexp.')\b((?:[^\[\]]|(?R)|.)*?)(?:(\/))?\](?:(.+?)\[\/\2\])?(.?) 

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

До:

 add_filter('the_content', 'do_shortcode', 11); // AFTER wpautop() 

После:

 add_filter('the_content', 'do_shortcode', 9); 

Я отправил это на трассу и на какое-то постоянное перерыв. Между тем, я думаю, могу ли я сделать плагин для применения моего исправления без изменения основных файлов. Переопределить приоритет фильтра легко, но я не знаю, как переопределить регулярное выражение.

Это было бы неплохо исправить! У меня недостаточно комментариев для комментариев, поэтому я оставляю следующую связанную ссылку WordPress trac, возможно, это то же самое, что и вы: http://core.trac.wordpress.org/ticket/14481

Я надеюсь, что любое исправление позволит использовать синтаксис короткого кода, например

[shortcode att1 = "val] ue"] content [/ shortcode]

так как в 3.0.1 содержимое% неправильно анализируется как ue"]content а не только content

Обновление : после того, как мы потратили время на изучение реестров (регулярных выражений?), Я позволил разрешить] и каскады с экранами в стиле Паскаля (например, arg = 'that' is [so] great ') в этих аргументах с двумя изменениями: сначала измените (.*?) в первом регулярном выражении ( get_shortcode_regex ) до

 ((?: [^ '"\]] | '[^'] *' | "[^"] *") *)

(NB: убедитесь, что вы избегаете все правильно в своем php-коде), то в shortcode_parse_atts (функция, содержащая второе регулярное выражение) измените следующее (опять же, измените ' на \' если вы используете однокадровый $pattern как в исходном коде)

 в $ pattern change "([^"] *) "to" ((?: [^ "] |" ") *)"
 в $ pattern change '([^'] *) 'to' ((?: [^ '] |' ') *)'
 $ atts [strtolower ($ m [1])] = preg_replace ('_ "" _', '"', stripcslashes ($ m [2]));
 $ atts [strtolower ($ m [3])] = preg_replace ("_''_", "'", stripcslashes ($ m [4]));

NB снова: изменения в шаблоне могут опираться на жадный характер сопоставления, поэтому, если этот параметр когда-либо изменен, измененные биты $pattern могут быть завершены чем-то вроде (?!") т. Д.