bbCode in an another - php

I made a custom function which acts like bbCode. I'm using preg_replace and regex. The only problem is that if I use more than one bbCode formatting, then just only one works..
[align=center][img]myimagelink[/img][/align]
If I enter this line, then the image appears BUT the [align=center]image[/align] also. How can I avoid this problem?
$patterns[2] = '#\[align=(.*)\](.*)\[\/align\]#si';
$patterns[9] = '#\[img\](.*\.jpg)\[\/img\]#si';
$replacements[2] = '<table align=\1><tr><td align=\1>\2</td></tr></table>';//ALIGN
$replacements[9] = '<img src=\"$1\"/>';//image

Changing the .* expressions to non-greedy (.*?) will work for you.
Example:
$in = '[align=center][img]myimagelink[/img][/align]';
$patterns = array(
'~\[align=(left|right|center)\](.*?)\[/align\]~' => '<div style="text-align: $1">$2</div>',
'~\[img](.*?)\[/img\]~' => '<img src="$1" />',
);
$rep = preg_replace(array_keys($patterns), $patterns, $in);
echo htmlspecialchars($rep);

Rather than reinventing the wheel I recommend using an existing javascript library.
I believe StackOverflow uses Prettify to format user input.

As #nickb stated, your patterns are greedy. (.*) grabs everything. Try changing it to (.*?).

treat all tags as singles not pairs
$patterns[2] = '#\[align=(.*)\]#si';
$patterns[3] = '#\[\/align\]#si';
$patterns[9] = '#\[img\](.*\.jpg)\[\/img\]#si';
$replacements[2] = '<div align=\"$1\">';//ALIGN
$replacements[3] = '</div>';//ALIGN
$replacements[9] = '<img src=\"$1\"/>';//image

Related

PHP and Simple DOM HTML Parser - Replace identical text string

I'm using the Simple DOM html parser php script in what seems to be a simple way, here's my code:
include('simple_html_dom.php');
$html = file_get_html($_SERVER['DOCUMENT_ROOT']."/wp-content/themes/genesis-sample-develop/cache-reports/atudem.html");
$snow_depth_min = $html->find('td', 115);
$snow_depth_max = $html->find('td', 116);
$snow_type = $html->find('td', 117);
The problem is with $snow_type. Sometimes the parsed text string is 'polvo' and sometimes it is 'polvo-dura'. I'm trying to replace 'polvo' with 'powder', and 'polvo-dura' with 'powder/packed'. If I do something like
if ($snow_type->innertext=='polvo-dura') {
$snow_type->innertext('powder');
}
or
$snow_type = str_replace("polvo", "powder", $snow_type);
$snow_type = str_replace("polvo-dura", "powder/packed", $snow_type);
it ends up with results like 'powder-dura' and weird things like that.
Obviously I'm new to php, so have some pattience with me ;) I would also like to understand why this happens and why a possible solution would work.
Thanks in advance
if ($snow_type->innertext=='polvo-dura') {
$innertext = 'powder/packed';
} else if ($snow_type->innertext=='polvo') {
$innertext = 'powder';
}
Provisional solution, using indexed arrays with preg_replace() :
$patterns = array();
$patterns[0] = '/-/';
$patterns[1] = '/polvo/';
$patterns[2] = '/dura/';
$replacements = array();
$replacements[0] = '/';
$replacements[1] = 'powder';
$replacements[2] = 'packed';
$snow_type_spanish_english = preg_replace($patterns, $replacements, $snow_type);
I have serious concerns about how it would work in real-world long complex texts, but for short-type data such as 'snow type' with values like 'a', 'b', 'a/b' or 'b/a', this can be just fine.
It would be great if someone comes with a better solution. I've been searching all over Internet for days and haven't found any specific solutions for text-values with the same words at the beginning, like 'powder' and 'powder-packed' for example.

use php preg_replace to replace alt="20x20" with style="width:20;height:20;"

How would I use php preg_replace to parse a string of HTML and replace
alt="20x20" with style="width:20;height:20;"
Any help is appreciated.
I tried this.
$pattern = '/(<img.*) alt="(\d+)x(\d+)"(.*style=")(.*)$/';
$style = '$1$4width:$2px;height:$3px;$5';
$text = preg_replace($pattern, $style, $text);
You don't need preg_replace to do this. You can use str_replace
$html = '<img alt="20x20" />';
preg_match('/<img.*?alt="(.*?)".*>/',$html,$match);
$search = 'alt="' . $match[1] . '"';
list($width, $height) = explode('x', $match[1]);
if(is_numeric($width) && is_numeric($height))
{
$replace = 'style="width:' . $width . 'px;height:' . $height . 'px;"';
echo str_replace($search, $replace, $html);
}
Output:
<img style="width:20px;height:20px;">
If you insist on using regular expressions to alter HTML markup you'll no doubt get stuck sometime, at which point you'd do well to look into something like Python's beautiful soup, or possibly the goode olde tidy library, which I think comes included as part of the PHP spec. But for now:
<?php
$originalString = 'Your string containing <img src="xyz.png" alt="20x20">';
$patternToFind = '/alt="20x20"/i';
$replacementString = 'style="width:20;height:20;"';
preg_replace($patternToFind, $replacementString, $originalString);
?>
And since it seems a lot of people are mighty peeved at what seems to be a code request, you might check this link out for php.net's guidance. It's not always this clear in explaining PHP's constructs, but would have solved your problem easily in this case:
http://php.net/manual/en/function.preg-replace.php
As mentioned in the comments you should use DOM to manipulate HTML codes.
If you want to do this by preg_replace anyway, I'd suggest to find out the regex by yourself with the help of sites like this one.

preg_replace : how get what is replaced

I want to show cards from regex codes :
ah displays As of hearts,
kc displays King of clubs
...
I used preg_replace() to do that in this way :
$arr = array('ah', 'kh', 'qh', ..., '3c', '2c');
$regex = '';
foreach ($arr as $i => $card)
{
$regex .= $card;
if ($i < count($arr) - 1)
$regex .= '|';
}
$message = preg_replace('#('.$regex.')#', '<img src="'.$dontknow.'.png" class="card" alt="" />', $message);
I don't know what value put in the src attribute, I want to tell to preg_replace() "when you find 'ah' you put ah.png, if it's kc then $dontknow == 'kc' etc.
Someone could be bring me some help ?
You can do this:
$message = preg_replace('#('.$regex.')#',
'<img src="$1.png" class="card" alt="" />', $message);
Use $1 reference - it is a link to a first group that PHP matched through preg_replace
You just need to use $n in your replacement to reference to a certain matching group (n is a number).
Since we pulled out the big guns:
Let's use preg_quote() to escape regex reserved characters in your array
PHP has a great set of function to juggle with arrays, let's use implode() instead of that ugly loop
From the comments, I realised that you need to add word boundaries \b to prevent false matches like yeah being replaced to ye<img...>. See this demo
Code:
$message = 'foo qh bar';
$arr = array('ah', 'kh', 'qh', '3c', '2c');
$escaped_arr = array_map(function($v){
return preg_quote($v, '#');
}, $arr); // Anonymous function requires PHP 5.3+
$message = preg_replace('#\b('.implode('|', $escaped_arr).')\b#', '<img src="$1.png" class="card" alt="" />', $message);
echo $message;
Online demo
You don't need that for loop. Here's a slightly improved version with the correct regex.
$arr = array('ah', 'kh', 'qh', ..., '3c', '2c');
$message = preg_replace('/('. implode('|'. $regex) .')/is', '<img src="$1.png" class="card" alt="" />', $message);
You should improve your 'markers' indicating the playing cards, by adding a special character (like # in the following example) to them. This will protect you from inadvertently changing other text passages:
$arr = array('ah', 'kh', 'qh', 'ac', '3c', '2c');
$txt = 'This is a line with cards #ah and #qh but with a potential head-ache.';
$rx = '##('.join('|',$arr).')#';
echo preg_replace($rx,"<img src=$1.jpg>",$txt);

PHP: Identical String not being matched together, something to do with (

I am stuck working on a function that translates HTML to bbcode.
I have written my own [spoiler] bbcode tag which translates properly into the HTML equivalent.
But when I try to turn it back into bbcode it doesn't seem to match seemingly identical strings...
After slowly rebuilding it piece by piece to see where the problem is, it turns out that it only fails when I add onclick="showSpoiler(this)"
to
#<div><input type="button" onclick="showSpoiler(this)"/><div>(.*)</div></div>#ig'
I narrowed it further down to the ( brackets. I have tried to escape them like this \(
the html code that is generated from the [spoiler] tag is:
`$1
and the string that it is matched against is this
'#<div><input type="button" onclick="showSpoiler(this)"/><div>(.*)</div></div>#ig'
here are the conversion functions
<?php
//This function let convert BBcode to HTML
function bbcode_to_html($text)
{
$text = nl2br(htmlentities($text, ENT_QUOTES, 'UTF-8'));
$in = array(
'#\[b\](.*)\[/b\]#Usi',
'#\[i\](.*)\[/i\]#Usi',
'#\[u\](.*)\[/u\]#Usi',
'#\[s\](.*)\[/s\]#Usi',
'#\[img\](.*)\[/img\]#Usi',
'#\[url\]((ht|f)tps?\:\/\/(.*))\[/url\]#Usi',
'#\[url=((ht|f)tps?\:\/\/(.*))\](.*)\[/url\]#Usi',
'#\[left\](.*)\[/left\]#Usi',
'#\[center\](.*)\[/center\]#Usi',
'#\[right\](.*)\[/right\]#Usi',
'#\[spoiler\](.*)\[/spoiler\]#Usi',
'#\[fuck\](.*)\[/fuck\]#Usi'
);
$out = array(
'<strong>$1</strong>',
'<em>$1</em>',
'<span style="text-decoration:underline;">$1</span>',
'<span style="text-decoration:line-through;">$1</span>',
'<img src="$1" alt="Image" />',
'$1',
'$4',
'<div style="text-align:left;">$1</div>',
'<div style="text-align:center;">$1</div>',
'<div style="text-align:right;">$1</div>',
'<div><input type="button" onclick="showSpoiler(this)" value="Show/Hide" /><div class="inner" style="display:none;">$1</div></div>',
'<div><input type="button" onclick="showSpoiler(this)"/><div>$1</div></div>'
);
$count = count($in)-1;
for($i=0;$i<=$count;$i++)
{
$text = preg_replace($in[$i],$out[$i],$text);
}
return $text;
}
//This function let convert HTML to BBcode
function html_to_bbcode($text)
{
$text = str_replace('<br />','',$text);
$in = array(
'#<strong>(.*)</strong>#Usi',
'#<em>(.*)</em>#Usi',
'#<span style="text-decoration:underline;">(.*)</span>#Usi',
'#<span style="text-decoration:line-through;">(.*)</span>#Usi',
'#<img src="(.*)" alt="Image" />#Usi',
'#(.*)#Usi',
'#<div style="text-align:left;">(.*)</div>#Usi',
'#<div style="text-align:center;">(.*)</div>#Usi',
'#<div style="text-align:right;">(.*)</div>#Usi',
'#<div><input type="button" onclick="showSpoiler(this)" value="Show/Hide" /><div class="inner" style="display:none;">(.*)</div></div>#Ui',
'#<div><input type="button" onclick="showSpoiler(this)"/><div>(.*)</div></div>#ig'
);
$out = array(
'[b]$1[/b]',
'[i]$1[/i]',
'[u]$1[/u]',
'[s]$1[/s]',
'[img]$1[/img]',
'[url=$1]$2[/url]',
'[left]$1[/left]',
'[center]$1[/center]',
'[right]$1[/right]',
'[spoiler]$1[/spoiler]',
'[fuck]$1[/fuck]'
);
$count = count($in)-1;
for($i=0;$i<=$count;$i++)
{
$text = preg_replace($in[$i],$out[$i],$text);
}
return $text;
}
?>
In your regex you need to escape the braces like so:
showSpoiler\(this\)
Take care with regular expressions, they are a language on it's own and hard to debug unless you add more functions that do the debugging (e.g. what was matched, output that etc.).
BTW you can run multiple search and replace operations by directly passing the arrays into the function. You don't need to iterate over them.
So better read the manual page about preg_replace again and look forward how you can more easily debug your patterns. E.g. test them before putting them into the function and similar.

Smiley Replace within CDATA of an HTML-String

i have got a simple problem :( I need to replace text smilies with the according smiley-image. ok.. thats not really complex, but now i have to replace only smilie appereances outside of HTML Tags. short examplae:
Text:
Thats a good example :/ .. with a link inside.
i want to replace ":/" with the image of this smiley...
ok, how to do that the best way?
I won't try to create some super script but think about it.... smilies are just about always surrounded by spaces. So str replace ' :/ ' with the smiley. You could be saying "what about a smiley at the end of a sentence(where it would be used the most)". Well just check for at least one space on either the left or the right of a potential smiley.
Using the above scripts:
$smiley_array = array(
":) " => "<a href...>",
" :)" => "<a href...>",
":/ " => "<a href...>",
" :/" => "<a href...>");
$codes = array_keys($smiley_array);
$links = array_values($smiley_array);
$str = str_replace($codes, $links, $str);
If you rather not have to type everything twice you can generate the array from a single smiley array.
Why don't you just try to use some special chars around your smiley text like this maybe -:/-
This will make your smiley text some kind of unique and easy to recognize
Use preg_replace with a lookbehind assertion. Example:
$smileys = array(
':/' => '<img src="..." alt=":/">'
);
foreach ($smileys as $smile => $img) {
$text = preg_replace('#(?<!<[^<>]*)' . preg_quote($smile, '#') . '#',
$img, $text);
}
The regex should match only smileys that are not inside angle brackets. This might be slow if you have a lot of false positives.
I wouldn't know about the best way, only the way I would do it.
Build an array having the smiley codes as the keys and the link as the value. The use str_replace. Pass as "needle" an array of the keys (the smiley codes) and as "replace" an array of the values.
For instance, suppose you have something like this:
$smiley_array = array(":)" => "<a href...>",
":(" => "<a href=....>");
$codes = array_keys($smiley_array);
$links = array_values($smiley_array);
$str = str_replace($codes, $links, $str);
EDIT: In case this could accidentally replace other instances with smiley-links you should consider using regexes with preg_replace. Obviously preg_replace is slower than str_replace.
You can use regex, or the extra sloppy version of the above:
$smiley_array = array(":)" => "<a href...>",
":(" => "<a href=....>");
$codes = array_keys($smiley_array);
$links = array_values($smiley_array);
$str = str_replace("://", "%%QF%%", $str);
$str = str_replace($codes, $links, $str);
$str = str_replace("%%QF%%", "://", $str);
Actually, assuming str_replace follows the array sorting...
this should work:
$smiley_array = array("://" => "%%QF%%", ":)" => "<a href...>",
":(" => "<a href=....>", "%%QF%%" => "://");
$codes = array_keys($smiley_array);
$links = array_values($smiley_array);
$str = str_replace($codes, $links, $str);
Possible overkill (increased cpu/load), but 99.99999999% safe:
<?php
$n = new DOMDocument();
$n->loadHTML('<p>Thats a good example :/ .. with a link inside.</p>');
$x = new DOMXPath($n);
$instances = $x->query('//text()[contains(.,\':/\')]');//or use '//*[child::text()]' for all textnodes
foreach($instances as $node){
if($node instanceof DOMText && preg_match_all('/:\//',$node->wholeText,$matches,PREG_OFFSET_CAPTURE|PREG_SET_ORDER)){
foreach($matches[0] as $match){
$newnode = $node->splitText($match[1]);
$newnode->replaceData(0,strlen($match[0]),'');
$img = $n->createElement('img');
$img->setAttribute('src','smily.gif');
$img = $newnode->parentNode->insertBefore($img,$newnode);
//var_dump($match);
}
}
}
var_dump($n->saveHTML());
?>
But in reality you do not want to do this all that often, save once, show many, if you are letting users edit the html (beit in wysiwyg or elsewise, the 'return' transformation (img to text) is a whole lot lighter. Up to you to expand with different smilies (one monster regex to match them, or several smaller ones / strstr()'s for readability, and a array for smiley to src (e.g. array(':/'=>'frown.gif')) would be the way to go.

Categories