2

I’m trying to insert a programmatically generated id attribute into child elements of parsedown processed text. I'm aware that Craft’s twig replace filter incorporates preg_replace, so…

I have a regex search string that finds an HTML tag and its contents. It includes an inner back reference to make sure that the closing tag matches the opening tag (as opposed to some nested closing tag)…

(<([a-z][a-z0-9]*)\b[^>]*>(.*?)</\2>)\s+

I can use $1 inside |replace to refer to the entire tag found by the outer parentheses…

elems|replace('/(<([a-z][a-z0-9]*)\\b[^>]*>(.*?)</\\2>)\s/', '$1>,')

…and then work with the results, but the problem (I think) is the syntax for the back reference inside the search string itself.

I've tried the following without success…

elems|replace('/(<([a-z][a-z0-9]*)\\b[^>]*>(.*?)</$2>)\s/', '$1>,') elems|replace('/(<([a-z][a-z0-9]*)\\b[^>]*>(.*?)</\\$2>)\s/', '$1>,')

Where am I going wrong? Is this even possible with preg_replace? Or is there a better way to go about injecting attributes into parsedown processed text?

  • The idea of the above is to prepare the ground for converting the parsedown output (elems) into an array, and then loop through the array to insert an id attribute, and then join the array to achieve the final output. – Jonathan Schofield Mar 22 '17 at 17:41
1

Backreferences within the regex are normally defined as \1, \2, etc. In the |replace filter you need to escape all backslashes, so it’ll be \\1, \\2, etc.

| improve this answer | |
  • Thanks, Brandon. I've tried that but it didn't work. I probably did something wrong. – Jonathan Schofield Mar 22 '17 at 18:01
  • I've realised that if I don't mind adding an attribute to all parsedown generated tags, as opposed to child tags only (no nested tags), then I don't need to worry about the closing tag at all, and therefore the back reference within the pattern. Which means I have something that works. – Jonathan Schofield Mar 22 '17 at 18:04
  • If I use the following (as per your suggestion I think)… elems|replace('/(<([a-z][a-z0-9]*)\\b[^>]*>(.*?)</\\2>)\s+/', '\\1>,'), then I get preg_replace(): Unknown modifier '\'. – Jonathan Schofield Mar 22 '17 at 18:08
  • @JonathanSchofield </ probably needs to be <\\/ – Brandon Kelly Mar 22 '17 at 18:08
  • Thanks. At least <\\/\\2> stops an error being thrown. But the HTML tag search fails. Thanks for your help. I may persist, or I might just go with my workaround. – Jonathan Schofield Mar 22 '17 at 18:27
1

A workaround in light of my comments on Brandon’s reply…

If I ignore the attempt to act on child tags only, I can search for opening tags of all generated elements (regardless of whether they are nested) with…

{% set elems = elems|replace('/(<[a-z][a-z0-9]*\\b[^>]*>)/', '$1>,') %}

and then…

{# Convert elems to an array #}
    {% set elems = elems|split('>,') %}

{% for el in elems %}
    {# Add an id attribute to each opening tag -- eg: id="el123-1" #}
    {{ el|replace('/(<[a-z][a-z0-9]*)/', '$1 id="el' ~ blockId ~ '-' ~ loop.index ~ '"')|raw }}
{% endfor %}
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.