Customise time in preg_replace - php

I have a form where users can quote others using bbcode. When somebody push quote button, the textarea value is :
[quote user=User date=1348246887 post=301]
User post text
[/quote]
And now, my code to transform into a block is :
$post = preg_replace("/\[quote user=(.*) date=(.*) post=(.*)](.*)\[\/quote\]/Uis", "<div class=\"quote\"><p>Quote by \\1 at time : \\2 </p><span>\\4</span></div>", $post);
How can i convert the time to date into preg_replace ? In preg_replace i can't do it, because the value of \2 is not set.

Try something like this (I added "test" inside the link, so you could see the link--not sure what you wanted there, but a non-breaking space won't make the link visible.) I used htmlentities for security in case the "subiect" $_GET variable (which maybe you meant to be "subject"?) contained markup or quotes. And of course, you can customize the date() string first argument to your needs. Finally, I added \s+ to allow for more flexible whitespacing. I also changed delimiter '/' to '#' so you don't need to escape '/' within the regex.
Updated for older PHP compatibility:
<?php
$post = <<<HERE
[quote user=User date=1348246887 post=301]
User post text
[/quote]
HERE;
// ] (just adding this comment to fix SO syntax colorer)
function replacer ($matches) {
return '<div class="quote"><p>Quote by '.$matches[1].' at time : '.
date('Y m d', $matches[2]).'<a href="index.php?subject='.
htmlentities($_GET['subiect'], ENT_COMPAT, 'UTF-8').
'&post='.$matches[3].'">test </a></p><span>'.
$matches[4].'</span></div>';
}
$post = preg_replace_callback(
'#\[quote\s+user=(.*)\s+date=(.*)\s+post=(.*)](.*)\[/quote\]#Uis',
'replacer',
$post
);
var_dump($post);
?>

Related

How to use preg_replace with url encoded $_GET?

I have a an url which looks like this https://URL.DOMAIN/blog.php?id=43&q=echo%20%27test%27.
When I use <?php echo $_GET['q'] ?> it displays echo 'test' which is what I want.
I am using this variable inside a preg_replace function which is basically made to apply a yellow background under matched strings:
preg_replace('/\b('.$_GET['q'].')\b/iu', '<span class="research-news-found">$1</span>', $news_content);
It works perfectly for "normal" strings like "apple" or whatever, but when there is a ' inside the search query it doesn't match anything.
Code example
$news_content = $news_display['news_description'];
if(isset($_GET['q'])){
$news_content = preg_replace('/\b('.$_GET['q'].')\b/iu', '<span class="research-news-found">$1</span>', $news_content);
}
$news_display['news_description'] contains the text output from DB.
Just make the pattern greedy ? and remove the trailing word boundary \b since ' is not a word character and is a word boundary:
$news_content = preg_replace('/\b('.$_GET['q'].'?)/iu',
'<span class="research-news-found">$1</span>',
$news_content);
Demo
But if you are hoping that it will actually echo test, then no. You would need to restructure your question to state what you want to achieve, not how to get this replacement to work.

how to do echo from a string, only from values that are between a specific stretch[href tag] of the string?

[PHP]I have a variable for storing strings (a BIIGGG page source code as string), I want to echo only interesting strings (that I need to extract to use in a project, dozens of them), and they are inside the quotation marks of the tag
but I just want to capture the values that start with the letter: N (news)
[<a href="/news7044449/exclusive_news_sunday_"]
<a href="/n[ews7044449/exclusive_news_sunday_]"
that is, I think you will have to work with match using: [a href="/n]
how to do that to define that the echo will delete all the texts of the variable, showing only:
note that there are other hrefs tags with values that start with other letters, such as the letter 'P' : href="/profiles... (This does not interest me.)
$string = '</div><span class="news-hd-mark">HD</span></div><p>exclusive_news_sunday_</p><p class="metadata"><span class="bg">Czech AV<span class="mobile-hide"> - 5.4M Views</span>
- <span class="duration">7 min</span></span></p></div><script>xv.thumbs.preparenews(7044449);</script>
<div id="news_31720715" class="thumb-block "><div class="thumb-inside"><div class="thumb"><a href="/news31720715/my_sister_running_every_single_morning"><img src="https://static-hw.xnewss.com/img/lightbox/lightbox-blank.gif"';
I imagine something like this:
$removes_everything_except_values_from_the_href_tag_starting_with_the_letter_n = ('/something regex expresion I think /' or preg_match, substring?);
echo $string = str_replace($removes_everything_except_values_from_the_href_tag_starting_with_the_letter_n,'',$string);
expected output: /news7044449/exclusive_news_sunday_
NOTE: it is not essential to be through a variable, it can be from a .txt file the place where the extracts will be extracted, and not necessarily a variable.
thanks.
I believe this will help her.
<?php
$source = file_get_contents("code.html");
preg_match_all("/<a href=\"(\/n(?:.+?))\"[^>]*>/", $source, $results);
var_export( end($results) );
Step by Step Regex:
Regex Demo
Regex Debugger
To get just the links out of the $results array from Valdeir's answer:
foreach ($results as $r) {
echo $r;
// alt: to display them with an HTML break tag after each one
echo $r."<br>\n";
}

nl2br for paragraphs

$variable = 'Afrikaans
Shqip - Albanian
Euskara - Basque';
How do I convert each new line to paragraph?
$variable should become:
<p>Afrikaans</p>
<p>Shqip - Albanian</p>
<p>Euskara - Basque</p>
Try this:
$variable = str_replace("\n", "</p>\n<p>", '<p>'.$variable.'</p>');
The following should do the trick :
$variable = '<p>' . str_replace("\n", "</p><p>", $variable) . '</p>';
Be careful, with the other proposals, some line breaks are not catch.
This function works on Windows, Linux or MacOS :
function nl2p($txt){
return str_replace(["\r\n", "\n\r", "\n", "\r"], '</p><p>', '<p>' . $txt . '</p>');
}
$array = explode("\n", $variable);
$newVariable = '<p>'.implode('</p><p>', $array).'</p>'
<?php
$variable = 'Afrikaans
Shqip - Albanian
Euskara - Basque';
$prep0 = str_replace(array("\r\n" , "\n\r") , "\n" , $variable);
$prep1 = str_replace("\r" , "\n" , $prep0);
$prep2 = preg_replace(array('/\n\s+/' , '/\s+\n/') , "\n" , trim($prep1));
$result = '<p>'.str_replace("\n", "</p>\n<p>", $prep2).'</p>';
echo $result;
/*
<p>Afrikaans</p>
<p>Shqip - Albanian</p>
<p>Euskara - Basque</p>
*/
?>
Explanation:
$prep0 and $prep1: Make sure each line ends with \n.
$prep2: Remove redundant whitespace. Keep linebreaks.
$result: Add p tags.
If you don't include $prep0, $prep1 and $prep2, $result will look like this:
<p>Afrikaans
</p>
<p>Shqip - Albanian
</p>
<p>Euskara - Basque</p>
Not very nice, I think.
Also, don't use preg_replace unless you have to. In most cases, str_replace is faster (at least according to my experience). See the comments below for more information.
Try:
$variable = 'Afrikaans
Shqip - Albanian
Euskara - Basque';
$result = preg_replace("/\r\n/", "<p>$1</p>", $variable);
echo $result;
I know this is a very old thread, but I want to highlight, that suggested solutions can have some issues in HTML world:
They do not check whether there is already a p tag around respective paragraph. This can result in extra paragraphs. At least some browsers will then show this as extra paragraphs, meaning <p>line1<p>line2</p>line3</p> will result in 3 paragraphs, which may not be the intention.
In fact, there is a bunch of tags, that are not expected inside of p, as per the spec of phrasing content. Or rather there is a limited set of tags, tha can be.
They will change new lines inside tags, where you want to preserve new lines as is. pre and textarea are the ones, where you could generally want that. code, samp, kbd and var are an example of other common values, but technically it can be any tag with white-space CSS property set to either pre, pre-wrap, pre-line or break-spaces.
They usually only check for \r\n or just \r or \n, while there are actually more symbols, that would mean new line, and they also have respective HTML entities, which can easily occur in HTML string.
To "combat" these flaws, at least, to an extent, I've just released a nl2tag library, which can also "convert" new lines to <li> items and has an "improved" nl2br logic (mostly for the sake of whitespace retention).
It's far from perfect (check the readme for limitations), but should cover you in case of relatively simple HTML string.

Regex Replace with Backreference modified by functions

I want to replace the class with the div text like this :
This: <div class="grid-flags" >FOO</div>
Becomes: <div class="iconFoo" ></div>
So the class is changed to "icon". ucfirst(strtolower(FOO)) and the text is removed
Test HTML
<div class="grid-flags" >FOO</div>
Pattern
'/class=\"grid-flags\" \>(FOO|BAR|BAZ)/e'
Replacement
'class="icon'.ucfirst(strtolower($1).'"'
This is one example of a replacement string I've tried out of seemingly hundreds. I read that the /e modifier evaluates the PHP code but I don't understand how it works in my case because I need the double quotes around the class name so I'm lost as to which way to do this.
I tried variations on the backref eg. strtolower('$1'), strtolower('\1'), strtolower('{$1}')
I've tried single and double quotes and various escaping etc and nothing has worked yet.
I even tried preg_replace_callback() with no luck
function callback($matches){
return 'class="icon"'.ucfirst(strtolower($matches[0])).'"';
}
It was difficult for me to try to work out what you meant, but I think you want something like this:
preg_replace('/class="grid-flags" \>(FOO|BAR|BAZ)/e',
'\'class="icon\'.ucfirst(strtolower("$1")).\'">\'',
$text);
Output for your example input:
<div class="iconFoo"></div>
If this isn't what you want, could you please give us some example inputs and outputs?
And I have to agree that this would be easier with an HTML parser.
Instead of using the e(valuate) option you can use preg_replace_callback().
$text = '<div class="grid-flags" >FOO</div>';
$pattern = '/class="grid-flags" >(FOO|BAR|BAZ)/';
$myCB = function($cap) {
return 'class="icon'.ucfirst($cap[1]).'" >';
};
echo preg_replace_callback($pattern, $myCB, $text);
But instead of using regular expressions you might want to consider a more suitable parser for html like simple_html_dom or php's DOM extension.
This works for me
$html = '<div class="grid-flags" >FOO</div>';
echo preg_replace_callback(
'/class *= *\"grid-flags\" *\>(FOO|BAR|BAZ)/'
, create_function( '$matches', 'return \'class="icon\' . ucfirst(strtolower($matches[1])) .\'">\'.$matches[1];' )
, $html
);
Just be aware of the problems of parsing HTML with regex.

php preg_match_all html dates with slashes error

I've trying to preg_match_all a date with slashes in it sitting between 2 html tags; however its returning null.
here is the html:
> <td width='40%' align='right'class='SmallDimmedText'>Last Login: 11/14/2009</td>
Here is my preg_match_all() code
preg_match_all('/<td width=\'40%\' align=\'right\' class=\'SmallDimmedText\'>Last([a-zA-Z0-9\s\.\-\',]*)<\/td>/', $h, $table_content, PREG_PATTERN_ORDER);
where $h is the html above.
what am i doing wrong?
thanks in advance
It (from a quick glance) is because you are trying to match:
Last Login: 11/14/2009
With this regex:
Last([a-zA-Z0-9\s\.\-\',]*)
The regex doesn't contain the required characters of : and / which are included in the text string. Changing the required part of the regex to:
Last([a-zA-Z0-9\s\.\-\',:/]*)
Gives a match
Would it be better to simply use a DOM parser, and then preform the regex on the result of the DOM lookup? It makes for nicer regex...
EDIT
The other issue is that your HTML is:
...40%' align='right'class='SmallDimmedText'>...
Where there is no space between align='right' and class='SmallDimmedText'
However your regex for that section is:
...40%\' align=\'right\' class=\'SmallDimmedText\'>...
Where it is indicated there is a space.
Use a DOM Parser It will save you more headaches caused by subtle bugs than you can count.
Just to give you an idea on how simple it is to parse using Simple HTML DOM.
$html = str_get_html(...);
$elems = $html->find('.SmallDimmedText');
if ( count($elems->children()) != 1 ){
throw new Exception('Too many/few elements found');
}
$text = $elems->children(0)->plaintext;
//parsing here is only an example, but you have removed all
//the html so that any regex used is really simple.
$date = substr($text, strlen('Last Login: '));
$unixTime = strtotime($date);
I see at least two problems :
in your HTML string, there is no space between 'right' and class=, and there is one space there in your regex
you must add at least these 3 characters to the list of matched characters, between the [] :
':' (there is one between "Login" and the date),
' ' (there are spaces between "Last" and "Login", and between ":" and the date),
and '/' (between the date parts)
With this code, it seems to work better :
$h = "<td width='40%' align='right'class='SmallDimmedText'>Last Login: 11/14/2009</td>";
if (preg_match_all("#<td width='40%' align='right'class='SmallDimmedText'>Last([a-zA-Z0-9\s\.\-',: /]*)<\/td>#",
$h, $table_content, PREG_PATTERN_ORDER)) {
var_dump($table_content);
}
I get this output :
array
0 =>
array
0 => string '<td width='40%' align='right'class='SmallDimmedText'>Last Login: 11/14/2009</td>' (length=80)
1 =>
array
0 => string ' Login: 11/14/2009' (length=18)
Note I have also used :
# as a regex delimiter, to avoid having to escape slashes
" as a string delimiter, to avoid having to escape single quotes
My first suggestion would be to minimize the amount of text you have in the preg_match_all, why not just do between a ">" and a "<"? Second, I'd end up writing the regex like this, not sure if it helps:
/>.*[0-9]{1,2}/[0-9]{1,2}/[0-9]{2,4}</
That will look for the end of one tag, then any character, then a date, then the beginning of another tag.
I agree with Yacoby.
At the very least, remove all reference to any of the HTML specific and simply make the regex
preg_match_all('#Last Login: ([\d+/?]+)#', ...

Categories