String substitution using UUIDs
Posted on 21/8/08 by Felix Geisendörfer
Hey folks,
this is post #2 of my 30 day challenge. If you've ever written any non-trivial String processing code, you've probably ran into the situation where you wanted to exclude certain parts of your string for a certain operation. Usually that would mean you have to tokenize your string, or adjust the operation you want to run so it doesn't affect the part of the string you want to exclude from it. Both of those solutions can be fairly time intensive so I was looking for a shortcut and found one.
Let me make a practical example so this sounds less like hypothetical BS: Let's say you have written your own Textile-inspired parser, but you want to allow sections to remain untouched by the parser as well. My solution: Just substitute the parts you want to exclude from textile processing with UUIDs and put them back in afterwards:
static function substitue($regex, $text) {
preg_match_all($regex, $text, $matches);
if (empty($matches[0])) {
return array($text, array(), array());
}
$r = array();
foreach ($matches[0] as $match) {
$uuid = String::uuid();
$r[1][] = $uuid;
$r[2][] = $match;
$text = r($match, $uuid, $text);
}
$r[0] = $text;
return $r;
}
}
$html = 'This *is* my sample [literal]text for *this* post[/literal]!';
list($html, $uuids, $values) = Common::substitute('/\[literal\].+\[\/literal]/sU');
// $html is now: 'This *is* my sample 8ad0fe9-ec3c-4b0d-b314-7a111030b5da!';
$html = Textile::parse($html);
// $html is now: 'This <strong>is</strong> my sample 8ad0fe9-ec3c-4b0d-b314-7a111030b5da!';
$html = str_replace($uuids, $values, $html);
// $html is now: 'This <strong>is</strong> my sample [literal]text for *this* post[/literal]!';
I actually found having this little substitution method useful a few times in the past so I thought I share it ; ). Suggestions for improvements and other approaches are more then welcome!
-- Felix Geisendörfer aka the_undefined
PS: I have decided to allow myself to write my posts for the weekend the night before and have them auto-published. Otherwise my girlfriend is going to kill me ; ).
You can skip to the end and add a comment.
"du hast sicher schon alle 30 vorgeschrieben :-)"
English translation: You sure wrote every of the 30 [posts] in advance.
No he hasn't oli. ; ) I just got up at 8:30am today and the first thing that Felix did is bug me about reviewing his post. After all we ended up posting it 15secs before the 09:00am deadline. Hehehe!
Nice trick! Just one thing: Am I wrong or should it rather be Common::substitute('/\[literal\].+\[\/literal]/sU'); ??
$html = 'This *is* my sample [literal]text for *this* post[/literal]!';
$regex = '/\[literal\].+\[\/literal]/sU';
Simple & fast :
preg_match_all($regex, $html, $matches);
$html = preg_replace($regex, '%s', $html);
$html = Textile::parse($html);
$html = vsprintf($html, $matches[0]);
Simple & fast :
< ?php
$html = 'This *is* my sample [literal]text for *this* post[/literal]!';
$regex = '/\[literal\].+\[\/literal]/sU';
preg_match_all($regex, $html, $matches);
$html = preg_replace($regex, '%s', $html);
$html = Textile::parse($html);
$html = vsprintf($html, $matches[0]);
?>
@Fabio, you read my mind! :)
@Fabio, you may want to replace % with %% before doing the preg_replace()
Fabio: Excellent idea. My only issue with it is that it is somewhat possible user-received content will contain sprintf instructions which makes uuids better suited as placeholders.
Christoph Tavan: Shit, that's what you get for last minute changes ; ). Fixed now.
Felix, if you apply Fabio's solution and replace % with %% before doing the preg_replace() then you shouldn't have any problems with occurrences of % in the users content.
This post is too old. We do not allow comments here anymore in order to fight spam. If you have real feedback or questions for the post, please contact us.
du hast sicher schon alle 30 vorgeschrieben :-)