I guys,
I would like replace a text adding specific links on specific words.
So, I created a dynamic array like this:
$replace = array (
"ferrari" => 'ferrari',
"ferrari 2" => 'ferrari 2'
etc.
)
I found a way to replace the text using:
preg_replace(array_keys($replace), array_values($replace), $subject)
but if in the $subject there is the string "ferrari 2" it will be replaced with
[ferrari] instead of [ferrari 2].
How can I do an exact match?
Thanks a lot!
You may use the following solution:
$s = "he has a ferrari and ferrari 2 and what not."; // SAMPLE STRING
$replace = array ( // REPLACEMENTS ARRAY
"ferrari" => 'ferrari',
"ferrari 2" => 'ferrari 2'
);
$keys = array_map('strlen', array_keys($replace)); // SORTING BY KEY LENGTH
array_multisort($keys, SORT_DESC, $replace); // IN DESCENDING ORDER
$pat = '~' . implode("|", array_keys($replace)) . '~'; // BUILDING A PATTERN
echo $pat . "\n"; // => ~ferrari 2|ferrari~ - matches either ferrari 2 or ferrari
$res = preg_replace_callback($pat, function($m) use ($replace) { // REPLACING...
return isset($replace[$m[0]]) ? $replace[$m[0]] : $m[0]; // IF THE KEY EXISTS,
}, $s); // REPLACE WITH VALUE, ELSE KEEP THE MATCH
echo $res; // => he has a ferrari and ferrari 2 and what not.
See the PHP demo
change the order to:
$replace = array (
"ferrari 2" => 'ferrari 2'
"ferrari" => 'ferrari',
)
Usually when you replace, just changing the order to where the smallest keys are last solves a lot.
I imagine that the var $subject is like this:
$subject = 'ferrari ferrari 2';
Try with this:
$replace = array (
"/ferrari(?!\s+\d+)/" => 'ferrari',
"/ferrari 2/" => 'ferrari 2'
);
echo preg_replace(array_keys($replace), array_values($replace), $subject);
Related
I have the following string, eg: 'Hello [owner], we could not contact by phone [phone], it is correct?'.
Regex would like to return in the form of array, all that is within []. Inside the bracket will only alpha characters.
Return:
$array = [
0 => '[owner]',
1 => '[phone]'
];
How should I proceed to have this return in php?
Try:
$text = 'Hello [owner], we could not contact by phone [phone], it is correct?';
preg_match_all("/\[[^\]]*\]/", $text, $matches);
$result = $matches[0];
print_r($result);
Output:
Array
(
[0] => [owner]
[1] => [phone]
)
I'm assuming that the end goal of all of this is that you want to replace the [placeholder]s with some other text, so use preg_replace_callback instead:
<?php
$str = 'Hello [owner], we could not contact by phone [phone], it is correct?';
$fields = [
'owner' => 'pedrosalpr',
'phone' => '5556667777'
];
$str = preg_replace_callback('/\[([^\]]+)\]/', function($matches) use ($fields) {
if (isset($fields[$matches[1]])) {
return $fields[$matches[1]];
}
return $matches[0];
}, $str);
echo $str;
?>
Output:
Hello pedrosalpr, we could not contact by phone 5556667777, it is correct?
I have an array called $Bond:
$Bond = array (
'Sean Connery' => 'Dr. No',
'George Lazenby' => 'On Her Majesty\'s Secret Service',
'Roger Moore' => 'Live and Let Die',
'Timothy Dalton' => 'The Living Daylights',
'Pierce Brosnan' => 'GoldenEye',
'Daniel Craig' => 'Casino Royal'
);
I need to extract ONLY the last names from the Keys & print them as uppercase.
How in the world would I go about that?
This would loop through each item and give you the last name.
foreach($box as $k=>$v){
$lastName = explode(' ',$k)[1];
echo strtoupper($lastName);
}
This could break if you had someone with a name like "Mary Jo" or "Bobby Jo" as a first name. In that case you may have to make some changes if this is going to occur.
Edit. I implemented the end function to ensure the last name.
foreach($box as $k=>$v){
$lastName = explode(' ',$k);
echo strtoupper(end($lastName));
}
You can follow several ways you can make an array of keys with array_keys() and then go through your array of keys with a for(), split the name with explode() and convert to upper the last name (end($info)) with strtoupper(). See the code:
<?php
$Bond = array (
'Sean Connery' => 'Dr. No',
'George Lazenby' => 'On Her Majesty\'s Secret Service',
'Roger Moore' => 'Live and Let Die',
'Timothy Dalton' => 'The Living Daylights',
'Pierce Brosnan' => 'GoldenEye',
'Daniel Craig' => 'Casino Royal'
);
$array_keys = array_keys($Bond);
for($i = 0; $i < count($array_keys); $i++) {
$info = explode(' ', $array_keys[$i]);
echo strtoupper(end($info)) . "<br>\n";
}
?>
Or you can go to through your array with the foreach() split the name with explode() and convert to upper the last name (end($info)) with strtoupper() something like this:
<?php
$Bond = array (
'Sean Connery' => 'Dr. No',
'George Lazenby' => 'On Her Majesty\'s Secret Service',
'Roger Moore' => 'Live and Let Die',
'Timothy Dalton' => 'The Living Daylights',
'Pierce Brosnan' => 'GoldenEye',
'Daniel Craig' => 'Casino Royal'
);
foreach($Bond as $key => $value) {
$info = explode(' ', $key);
echo strtoupper(end($info)) . "<br>\n";
}
?>
Output in both cases:
CONNERY
LAZENBY
MOORE
DALTON
BROSNAN
CRAIG
Since the actor names fall on the keys, use foreach, then you could just use strrchr + substr to get the last name:
foreach($Bond as $name => $movie) {
$last = strtoupper(substr(strrchr($name, ' '), 1));
echo $last, '<br/>';
}
Sample Output
This should work for you, nice and compact:
(Here I go through all array keys with array_keys(), where I then explode() each key by a space as delimiter. And then access the last element which I return in strtoupper() case)
<?php
$lastNamesUpper = array_map(function($v){
return strtoupper(explode(" ", $v)[substr_count($v, " ")]);
}, array_keys($Bond));
foreach($lastNamesUpper as $v)
echo "$v<br>";
?>
output:
CONNERY
LAZENBY
MOORE
DALTON
BROSNAN
CRAIG
I have an array with several elements like this:
cars = array ("name" => "volkswagen", "description" => "hier by hidd by hisd by hidf by"
"name" => "fiat", "description" => "hier by hias by hisad by hiasd by");
how could replace elements in each array in each two occurrences description by half. That is the result:
carsModified = array ("name" => "volkswagen", "description" => "hier by hidd replace hisd by hidf replace"
"name" => "fiat", "description" => "hier by hias replace hisad by hiasd replace");
by substitutions for replace.
If I understood correctly, you have an array of the following format:
$arr = array (
array(
"name" => "volkswagen",
"description" => "hier by hidd by hisd by hidf by"
),
array(
"name" => "fiat",
"description" => "hier by hias by hisad by hiasd by"
)
);
Now, you want to modify the description field (or any other), which contains the word "by" with the word "replace". You want to replace only the even occurrences. For this, we will write a function that accepts a string and replaces every second occurrence of a string. There are many ways to do it, this is one:
function replace_evens($search, $replace, $subject){
$parsed = explode($search, $subject);
$doubles = array();
for ($i=0, $n=count($parsed); $i<$n-1; $i+=2){
$doubles[] = $parsed[$i] . $search .$parsed[$i+1];
}
if ($i==$n-1) $doubles[] = $parsed[$n-1];
return implode($replace, $doubles);
}
Now we will iterate over the array, and foreach element (which is also an array) we will go over all of it's fields. Notice the reference (&) before $a because we want to modify the same element and not clone it. Also notice that we append spaces around the value $v
foreach($arr as &$a){
foreach($a as $k=>$v){
$a[$k] = trim(replace_evens(' by ', ' replace ' , ' ' . $v. ' ' ));
}
}
print_r($arr);
Hope it helps. Take in mind that I did not test this code...
I have an array with a list of all controllers in my application:
$controllerlist = glob("../controllers/*_controller.php");
How do I strip ../controllers/ at the start and _controller.php at the end of each array element with one PHP command?
As preg_replace can act on an array, you could do:
$array = array(
"../controllers/test_controller.php",
"../controllers/hello_controller.php",
"../controllers/user_controller.php"
);
$array = preg_replace('~../controllers/(.+?)_controller.php~', "$1", $array);
print_r($array);
output:
Array
(
[0] => test
[1] => hello
[2] => user
)
Mapping one array to another:
$files = array(
'../controllers/test_controller.php',
'../controllers/hello_controller.php'
);
$start = strlen('../controllers/');
$end = strlen('_controller.php') * -1;
$controllers = array_map(
function($value) use ($start, $end) {
return substr($value, $start, $end);
},
$files
);
var_dump($controllers);
I'm not sure how you defined "command", but I doubt there is a way to do that with one simple function call.
However, if you're simply wanting it to be compact, here's a simple way of doing it:
$controllerlist = explode('|||', str_replace(array('../controllers/', '_controller.php'), '', implode('|||', glob("../controllers/*_controller.php"))));
It's a bit dirty, but it gets the job done in a single line.
One command without searching and replacing? Yes you can!
If I'm not missing something grande, what about keeping it simple and chopping 15 characters from the start and the end using the substr function:
substr ( $x , 15 , -15 )
Since glob will always give you strings with that pattern.
Example:
// test array (thanks FruityP)
$array = array(
"../controllers/test_controller.php",
"../controllers/hello_controller.php",
"../controllers/user_controller.php" );
foreach($array as $x){
$y=substr($x,15,-15); // Chop 15 characters from the start and end
print("$y\n");
}
Output:
test
hello
user
No need for regex in this case unless there can be variations of what you mentioned.
$array = array(
"../controllers/test_controller.php",
"../controllers/hello_controller.php",
"../controllers/user_controller.php"
);
// Actual one liner..
$list = str_replace(array('../controllers/', '_controller.php'), "", $array);
var_dump($array);
This will output
array (size=3)
0 => string 'test' (length=4)
1 => string 'hello' (length=5)
2 => string 'user' (length=4)
Which is (I think) what you asked for.
If you have an array like this :
$array = array( "../controllers/*_controller.php",
"../controllers/*_controller.php");
Then array_map() help you to trim the unnecessary string.
function trimmer( $string ){
return str_replace( "../controllers/", "", $string );
}
$array = array( "../controllers/*_controller.php",
"../controllers/*_controller.php");
print_r( array_map( "trimmer", $array ) );
http://codepad.org/VO6kyVOa
to strip 15 chars at the start and 15 at the end of each arrayelement in one command:
$controllerlist = substr_replace(
substr_replace(
glob("../controllers/*_controller.php"),'',-15
),'',0,15
)
preg_replace accepts an array as argument too:
$before = '../controllers/';
$after = "_controller.php";
$preg_str = preg_quote($before,"/").'(.*)'.preg_quote($after,"/");
$controllerlist = preg_replace('/^'.$preg_str.'$/', '\1', glob("$before*$after"));
If I have a string that looks like this:
$myString = "[sometext][moretext][993][112]This is a long text";
I want it to be turned into:
$string = "This is a long text";
$arrayDigits[0] = 993;
$arrayDigits[1] = 112;
$arrayText[0] = "sometext";
$arrayText[1] = "moretext";
How can I do this with PHP?
I understand Regular Expressions is the solution. Please notice that $myString was just an example. There can be several brackets, not just two of each, as in my example.
Thanks for your help!
This is what I came up with.
<?php
#For better display
header("Content-Type: text/plain");
#The String
$myString = "[sometext][moretext][993][112]This is a long text";
#Initialize the array
$matches = array();
#Fill it with matches. It would populate $matches[1].
preg_match_all("|\[(.+?)\]|", $myString, $matches);
#Remove anything inside of square brackets, and assign to $string.
$string = preg_replace("|\[.+\]|", "", $myString);
#Display the results.
print_r($matches[1]);
print_r($string);
After that, you can iterate over the $matches array and check each value to assign it to a new array.
Try this:
$s = '[sometext][moretext][993][112]This is a long text';
preg_match_all('/\[(\w+)\]/', $s, $m);
$m[1] will contain all texts in the brakets, after this you could check type of each value. Also, you could check this using two preg_match_all: at first time with pattern /\[(\d+)\]/ (will return array of digits), in the second - pattern /\[([a-zA-z]+)\]/ (that will return words):
$s = '[sometext][moretext][993][112]This is a long text';
preg_match_all('/\[(\d+)\]/', $s, $matches);
$arrayOfDigits = $matches[1];
preg_match_all('/\[([a-zA-Z]+)\]/', $s, $matches);
$arrayOfWords = $matches[1];
For cases like yours you can make use of named subpatterns so to "tokenize" your string. With some little code, this can be made easily configurable with an array of tokens:
$subject = "[sometext][moretext][993][112]This is a long text";
$groups = array(
'digit' => '\[\d+]',
'text' => '\[\w+]',
'free' => '.+'
);
Each group contains the subpattern and it's name. They match in their order, so if the group digit matches, it won't give text a chance (which is necessary here because \d+ is a subset of \w+). This array can then turned into a full pattern:
foreach($groups as $name => &$subpattern)
$subpattern = sprintf('(?<%s>%s)', $name, $subpattern);
unset($subpattern);
$pattern = sprintf('/(?:%s)/', implode('|', $groups));
The pattern looks like this:
/(?:(?<digit>\[\d+])|(?<text>\[\w+])|(?<free>.+))/
Everything left to do is to execute it against your string, capture the matches and filter them for some normalized output:
if (preg_match_all($pattern, $subject, $matches))
{
$matches = array_intersect_key($matches, $groups);
$matches = array_map('array_filter', $matches);
$matches = array_map('array_values', $matches);
print_r($matches);
}
The matches are now nicely accessible in an array:
Array
(
[digit] => Array
(
[0] => [993]
[1] => [112]
)
[text] => Array
(
[0] => [sometext]
[1] => [moretext]
)
[free] => Array
(
[0] => This is a long text
)
)
The full example at once:
$subject = "[sometext][moretext][993][112]This is a long text";
$groups = array(
'digit' => '\[\d+]',
'text' => '\[\w+]',
'free' => '.+'
);
foreach($groups as $name => &$subpattern)
$subpattern = sprintf('(?<%s>%s)', $name, $subpattern);
unset($subpattern);
$pattern = sprintf('/(?:%s)/', implode('|', $groups));
if (preg_match_all($pattern, $subject, $matches))
{
$matches = array_intersect_key($matches, $groups);
$matches = array_map('array_filter', $matches);
$matches = array_map('array_values', $matches);
print_r($matches);
}
You could try something along the lines of:
<?php
function parseString($string) {
// identify data in brackets
static $pattern = '#(?:\[)([^\[\]]+)(?:\])#';
// result container
$t = array(
'string' => null,
'digits' => array(),
'text' => array(),
);
$t['string'] = preg_replace_callback($pattern, function($m) use(&$t) {
// shove matched string into digits/text groups
$t[is_numeric($m[1]) ? 'digits' : 'text'][] = $m[1];
// remove the brackets from the text
return '';
}, $string);
return $t;
}
$string = "[sometext][moretext][993][112]This is a long text";
$result = parseString($string);
var_dump($result);
/*
$result === array(
"string" => "This is a long text",
"digits" => array(
993,
112,
),
"text" => array(
"sometext",
"moretext",
),
);
*/
(PHP5.3 - using closures)