开发者

Recursive Contents of HTML tag using regex

I'm writing an application for my client that uses a WYSIWYG to allow employees to modify a letter template with certain variables that get parsed out to be information for the customer that the letter is written for.

The WYSIWYG generates HTML that I save to a SQL server database. I then use a PHP class to generate a PDF document with the template text.

Here's my issue. The PDF generation class can translate b,u,i HTML tags. That's it. This is mostly okay, except I need blockquote to be translated too. I figure the best solution would be to write a regex statement that is to take the contents of each blockquote HTML block, and replace each line within the block with five spaces. The trick is that some blockquotes might contain nested blockquotes (double indenting, and what not)

But unfortunately I have never been too well versed with regex, and I spent the last 1.5 hours experimenting with different patterns and got nothing working.

Here are the gotchyas:

  • String may or may not contain a blockquote block
  • String could contain multiple blockquotes
  • String could contain potentially any level of nesting of blockquotes blocks
  • We can rely on the HTML being properly formed

A sample input string would be look something like something like this:

Dear Charlie,<br><br>开发者_运维技巧;We are contacting you because blah blah blah blah.<br><br><br>To login, please use this information:<blockquote>Username: someUsername<br>Password: somePassword</blockquote><br><br>Thank you.

To simply the solution, I need to replace each HTML break inside each blockquote with 5 spaces and then the \n line break character.


You might want to check PHP Simple HTML DOM Parser out. You can use it to parse the input to an HTML DOM tree and use that.


~<blockquote>((?:[^<]*+(?:(?!<blockquote>)|(?R))*+)*+)</blockquote>~

You will need to run this regex recursively using preg_replace_callback:

const REGEX_BLOCKQUOTE = '~<blockquote>((?:[^<]*+(?:(?!<blockquote>)|(?R))*+)*+)</blockquote>~';
function blockquoteCallback($matches) {
    return doIndent(preg_replace_callback(REGEX_BLOCKQUOTE, __FUNCTION__, $matches[1]));
}

$output = preg_replace_callback(REGEX_BLOCKQUOTE, 'blockQuoteCallback', $input);

My regex assumes, that there won't be any attributes on the blockquote or anywhere else.

(PS: I'll leave the "Use a DOM parser" comment to someone else.)


Regular expressions have a theory behind them, and even though the modern day's regular expresison engine provide can provide a 'Type - 2.5' level language , some things are still not doable. In your partiular case, nesting is not achievable easily. A simple way way to explain this, is to say that regular expression can't keep a count .. i.e. they can't count the nesting level...

what is you need is a limited CFG ( the paren-counting types ) .. you need to somehow keep a count ..may be a stack or tree ...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜