Preg match question - php

I'm sure someone already asked this question, but after searching for more than 1 hour on google, I decided to ask my question here.
I want to itterate over an array excisting of different strings/texts.
These texts contain strings with both ##valuetoreplace## and #valuetoreplace#
I want to make to preg_matches:
$pattern = '/^#{1}+(\w+)+#{1}$/';
if(preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE))
{
// do something with the #values#
}
AND
$pattern = '/^#{2}+(\w+)+#{2}$/';
if(preg_match($pattern, $value, $matches, PREG_OFFSET_CAPTURE))
{
//do something with the ##value##
}
This works great.
Now my only problem is as follows:
When i have a string like
$valueToMatch = 'proceding text #value#';
My preg_match cant find my value anymore (as i used a ^ and a $).
Question: how can i find the #value# and the ##value##, without having to worry if these words are in the middle of a (multi-line) value?
*In addition:
What i want is to find patterns and replace the #value# with a db value and a ##value## with a array value.
For example:
$thingsToReplace = 'Hello #firstname# #lastname#,
How nice you joined ##namewebsite##.';
should be
'Hello John Doe,
How nice you joined example.com.'

Try this: /##([^#]+)##/ and /#([^#]+)#/, in that order.

Maybe nice to know for other visitors how i did it:
foreach($personalizeThis as $key => $value)
{
//Replace ##values##
$patternIniData = '/#{2}+(\w+)#{2}/';
$return = 'website'; //testdata
$replacedIniData[$key] = preg_replace($patternIniData, $return, $value);
//Replace #values#
$pattern = '/#{1}+(\w+)#{1}/';
$return = 'ASD'; //testdata
$replacedDbData[$key] = preg_replace($pattern, $return, $replacedIniData[$key]);
}
return $replacedDbData;

Related

PHP regex replace from string to string

I want to replace a section of a string based that starts with one string and ends with another, and I want the section between also replaced. I think this is possible using regex but I cant' seem to find any decent examples showing this.
For Example:
I have "http://www.website.com" and I want to replace from "www" to "com" with "123xyz".
So"http://www.website.com/something" becomes "http://123xyz/something.
I am assuming I have to use preg_replace(), and I think the regex should start with "^www" and end with "com$", but I cant seem to get a grasp of the syntax of regex enough to create the desired effect.
please help
With reference to your example , you can try like this
$string = 'http://www.website.com/something';
$pattern = '/www(.*)com/';
$replacement = '123xyz';
echo preg_replace($pattern, $replacement, $string);
$phrase = "http://www.website.com";
$phraseWords = array("www", "com");
$replaceTo = array("123xyz", "something");
$result = str_replace($phraseWords, $replaceTo, $phrase);
echo $result;
Thanks so much to both #CodingAnt and #PHPWeblineindia for your great answers. Using #CodingAnt's answer (and some more research I did online) I wrote this function:
function replaceBetween(&$target, $from, $to, $with){
if(strpos($target, $from)===false)return false;
$regex = "'".$from."(.*?)".$to."'si";
preg_match_all($regex, $target, $match);
$match = $match[1];
foreach($match as $m) $target = str_replace($from.$m.$to, $with, $target);
return $target;
}
It seems to work pretty well. I hope someone finds this useful.

regular expression word preceded by char

I want to grab a specific string only if a certain word is followed by a = sign.
Also, I want to get all the info after that = sign until a / is reached or the string ends.
Let's take into example:
somestring.bla/test=123/ohboy/item/item=capture
I want to get item=capture but not item alone.
I was thinking about using lookaheads but I'm not sure it this is the way to go. I appreciate any help as I'm trying to grasp more and more about regular expressions.
[^/=]*=[^/]*
will give you all the pairs that match your requirements.
So from your example it should return:
test=123
item=capture
Refiddle Demo
If you want to capture item=capture, it is straightforward:
/item=[^\/]*/
If you want to also extract the value,
/item=([^\/]*)/
If you only want to match the value, then you need to use a look-behind.
/(?<=item=)[^\/]*/
EDIT: too many errors due to insomnia. Also, screw PHP and its failure to disregard separators in a character group as separators.
Here is a function I wrote some time ago. I modified it a little, and added the $keys argument so that you can specify valid keys:
function getKeyValue($string, Array $keys = null) {
$keys = (empty($keys) ? '[\w\d]+' : implode('|', $keys));
$pattern = "/(?<=\/|$)(?P<key>{$keys})\s*=\s*(?P<value>.+?)(?=\/|$)/";
preg_match_all($pattern, $string, $matches, PREG_SET_ORDER);
foreach ($matches as & $match) {
foreach ($match as $key => $value) {
if (is_int($key)) {
unset($match[$key]);
}
}
}
return $matches ?: FALSE;
}
Just trow in the string and valid keys:
$string = 'somestring.bla/test=123/ohboy/item/item=capture';
$keys = array('test', 'item');
$keyValuePairs = getKeyValue($string, $keys);
var_dump($keyValuePairs);

Match words (regex) and create internal links from values stored in Array

What I am trying to achieve is the following:
When I create news items, I want php to check these items for keywords. These keywords are stored in a mysql table (2 fields: search = varchar(255), link = varchar(255)).
I use a query to get the results and store them in an array.
I want to find words in a string and add an anchor to the word. The important bit is (where I have difficulty with) is that the search has to be case insensitive.
For example:
$searchFor = array("sun","sunny","wind","crap");
$linkArray = array("/solar","/solar","/wind-energy","/toilet");
The string:
What do you know about the sun? Sun, what kind of word is that? Is it
something just like wind? Wind, another weird word. This text is
complete crap by the way.
What I want as a result is:
What do you know about the sun? Sun what kind of word is that? Is it something just like wind? Wind another weird word. This text is complete crap by the way.
The code I have is:
$string = 'What do you know about the sun? Sun, what kind of word is that? Is it something just like wind? Wind, another weird word. This text is complete crap by the way.';
$pattern = "/(\w+)/i";
preg_match_all($pattern, $string, $matches);
foreach($matches[0] as $i => $word)
{
$search = strtolower($word);
if(in_array($search,$searchFor))
{
$pos = array_search($search,$searchFor);
$link = $linkArray[$pos];
echo "{$word} ";
}
else
{
echo $word." ";
}
}
But I get stuck using regex (I think this is the right way).
$replacement = '${1}';
Is this possible??
Thank you.
Testet!
<?php
$searchFor = array("sun","sunny","wind","crap");
foreach($searchFor as $iKey => $sVal) {
$searchFor[$iKey] = "/(" . $sVal . ")/i";
}
$linkArray = array("/solar","/solar","/wind-energy","/toilet");
foreach($linkArray as $iKey => $sVal) {
$linkArray[$iKey] = '$1';
}
$string = 'What do you know about the sun? Sun, what kind of word is that? Is it something just like wind? Wind, another weird word. This text is complete crap by the way.';
echo preg_replace($searchFor, $linkArray, $string);

mb_eregi_replace multiple matches get them

$string = 'test check one two test3';
$result = mb_eregi_replace ( 'test|test2|test3' , '<$1>' ,$string ,'i');
echo $result;
This should deliver: <test> check one two <test3>
Is it possible to get, that test and test3 was found, without using another match function ?
You can use preg_replace_callback instead:
$string = 'test check one two test3';
$matches = array();
$result = preg_replace_callback('/test|test2|test3/i' , function($match) use ($matches) {
$matches[] = $match;
return '<'.$match[0].'>';
}, $string);
echo $result;
Here preg_replace_callback will call the passed callback function for each match of the pattern (note that its syntax differs from POSIX). In this case the callback function is an anonymous function that adds the match to the $matches array and returns the substitution string that the matches are to be replaced by.
Another approach would be to use preg_split to split the string at the matched delimiters while also capturing the delimiters:
$parts = preg_split('/test|test2|test3/i', $string, null, PREG_SPLIT_DELIM_CAPTURE);
The result is an array of alternating non-matching and matching parts.
As far as I know, eregi is deprecated.
You could do something like this:
<?php
$str = 'test check one two test3';
$to_match = array("test", "test2", "test3");
$rep = array();
foreach($to_match as $val){
$rep[$val] = "<$val>";
}
echo strtr($str, $rep);
?>
This too allows you to easily add more strings to replace.
Hi following function used to found the any word from string
<?php
function searchword($string, $words)
{
$matchFound = count($words);// use tha no of word you want to search
$tempMatch = 0;
foreach ( $words as $word )
{
preg_match('/'.$word.'/',$string,$matches);
//print_r($matches);
if(!empty($matches))
{
$tempMatch++;
}
}
if($tempMatch==$matchFound)
{
return "found";
}
else
{
return "notFound";
}
}
$string = "test check one two test3";
/*** an array of words to highlight ***/
$words = array('test', 'test3');
$string = searchword($string, $words);
echo $string;
?>
If your string is utf-8, you could use preg_replace instead
$string = 'test check one two test3';
$result = preg_replace('/(test3)|(test2)|(test)/ui' , '<$1>' ,$string);
echo $result;
Oviously with this kind of data to match the result will be suboptimal
<test> check one two <test>3
You'll need a longer approach than a direct search and replace with regular expressions (surely if your patterns are prefixes of other patterns)
To begin with, the code you want to enhance does not seem to comply with its initial purpose (not at least in my computer). You can try something like this:
$string = 'test check one two test3';
$result = mb_eregi_replace('(test|test2|test3)', '<\1>', $string);
echo $result;
I've removed the i flag (which of course makes little sense here). Still, you'd still need to make the expression greedy.
As for the original question, here's a little proof of concept:
function replace($match){
$GLOBALS['matches'][] = $match;
return "<$match>";
}
$string = 'test check one two test3';
$matches = array();
$result = mb_eregi_replace('(test|test2|test3)', 'replace(\'\1\')', $string, 'e');
var_dump($result, $matches);
Please note this code is horrible and potentially insecure. I'd honestly go with the preg_replace_callback() solution proposed by Gumbo.

In PHP, how do I extract multiple e-mail addresses from a block of text and put them into an array?

I have a block of text from which I want to extract the valid e-mail addresses and put them into an array. So far I have...
$string = file_get_contents("example.txt"); // Load text file contents
$matches = array(); //create array
$pattern = '/[A-Za-z0-9_-]+#[A-Za-z0-9_-]+\.([A-Za-z0-9_-][A-Za-z0-9_]+)/'; //regex for pattern of e-mail address
preg_match($pattern, $string, $matches); //find matching pattern
However, I am getting an array with only one address. Therefore, I am guessing I need to cycle through this process somehow. How do I do that?
You're pretty close, but the regex wouldn't catch all email formats, and you don't need to specify A-Za-z, you can just use the "i" flag to mark the entire expression as case insensitive. There are email format cases that are missed (especially subdomains), but this catches the ones I tested.
$string = file_get_contents("example.txt"); // Load text file contents
// don't need to preassign $matches, it's created dynamically
// this regex handles more email address formats like a+b#google.com.sg, and the i makes it case insensitive
$pattern = '/[a-z0-9_\-\+]+#[a-z0-9\-]+\.([a-z]{2,3})(?:\.[a-z]{2})?/i';
// preg_match_all returns an associative array
preg_match_all($pattern, $string, $matches);
// the data you want is in $matches[0], dump it with var_export() to see it
var_export($matches[0]);
output:
array (
0 => 'test1+2#gmail.com',
1 => 'test-2#yahoo.co.jp',
2 => 'test#test.com',
3 => 'test#test.co.uk',
4 => 'test#google.com.sg',
)
I know this is not the question you asked but I noticed that your regex is not accepting any address like 'myemail#office21.company.com' or any address with a subdomain. You could replace it with something like :
/[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}/
which will reject less valid e-mail (although it is not perfect).
I also suggest you read this article on e-mail validation, it is pretty good and informative.
Your code is almost perfect, you just need to replace preg_match(...) with preg_match_all(...)
http://www.php.net/manual/en/function.preg-match.php
http://www.php.net/manual/en/function.preg-match-all.php
This detects all mail addresses:
$sourceeee= 'Here are examplr mymail#yahoo.com and my-e.mail#goog.com or something more';
preg_match_all('/[A-Za-z0-9._%+-]+#[A-Za-z0-9.-]+\.[A-Za-z]{2,4}/i', $sourceeee, $found_mails);
then you can use $found_mails[0] array.
This regex will extract all unique email address from a url or file and output each in new line. It will consider all subdomains and prefix suffix issues. Find comfortable to use it.
<?
$url="http://example.com/";
$text=file_get_contents($url);
$res = preg_match_all(
"/[a-z0-9]+[_a-z0-9\.-]*[a-z0-9]+#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,4})/i",
$text,
$matches
);
if ($res) {
foreach(array_unique($matches[0]) as $email) {
echo $email . "<br />";
}
}
else {
echo "No emails found.";
}
?>
check here for more reference : http://www.php.net/manual/en/function.preg-match-all.php
It worked better for me:
<?php
$content = "Hi my name is Joe, I can be contacted at joe#mysite.com.";
preg_match("/[_a-z0-9-]+(\.[_a-z0-9-]+)*#[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})/i", $content, $matches);
print $matches[0];
?>
Some of the others didn't accept domains like: name#example.com.sv
I found it on: http://snipplr.com/view/63938/
This function works fine without using regex. So it is really faster and low resource hungry.
<?php
function extract_email_addresses($str){
$emails = array();
$str = strip_tags( $str );
$str = preg_replace('/\s+/', ' ', $str);
$str = preg_replace("/[\n\r]/", "", $str);
$remove_chars = array (',', "<", ">", ";", "'", ". ");
$str = str_replace( $remove_chars, ' ', $str );
$parts = explode(' ', $str);
if(count($parts) > 0){
foreach($parts as $part){
$part = trim($part);
if( $part != '' ) {
if( filter_var($part, FILTER_VALIDATE_EMAIL) !== false){
$emails[] = $part;
}
}
}
}
if(count($emails) > 0){
return $emails;
}
else{
return null;
}
}
$string = "Guys, please help me to extract valid sam-ple.1990#gmail.co.uk email addresses from some text content using php
example , i have below text content in mysql database ' Life is more beautiful, and i like to explore lot please email me to sample#gmail.com. Learn new things every day. 'from the above text content i want to extract email address 'sample-x#gmail.com' using php regular expressions or other method.";
$matches = extract_email_addresses( $string );
print_r($matches);
?>

Categories