PHP equivalent of Python's `str.format` method? - php

Is there an equivalent of Python str.format in PHP?
In Python:
"my {} {} cat".format("red", "fat")
All I see I can do in PHP natively is by naming the entries and using str_replace:
str_replace(array('{attr1}', '{attr2}'), array('red', 'fat'), 'my {attr1} {attr2} cat')
Is there any other PHP's native alternatives?

sprintf is the closest thing. It's the old-style Python string formatting:
sprintf("my %s %s cat", "red", "fat")

As PHP doesn't really have a proper alternative to str.format in Python, I decided to implement my very simple own which as most of the basic functionnalitites of the Python's one.
function format($msg, $vars)
{
$vars = (array)$vars;
$msg = preg_replace_callback('#\{\}#', function($r){
static $i = 0;
return '{'.($i++).'}';
}, $msg);
return str_replace(
array_map(function($k) {
return '{'.$k.'}';
}, array_keys($vars)),
array_values($vars),
$msg
);
}
# Samples:
# Hello foo and bar
echo format('Hello {} and {}.', array('foo', 'bar'));
# Hello Mom
echo format('Hello {}', 'Mom');
# Hello foo, bar and foo
echo format('Hello {}, {1} and {0}', array('foo', 'bar'));
# I'm not a fool nor a bar
echo format('I\'m not a {foo} nor a {}', array('foo' => 'fool', 'bar'));
The order doesn't matter,
You can omit the name/number if you want it to simply increment (the first {} matched will be transformed into {0}, etc),
You can name your parameters,
You can mix the three other points.

I know it's an old question, but I believe strtr with replace pairs deserves to be mentioned:
(PHP 4, PHP 5, PHP 7)
strtr — Translate characters or replace substrings
Description:
strtr ( string $str , string $from , string $to ) : string
strtr ( string $str , array $replace_pairs ) : string
<?php
var_dump(
strtr(
"test {test1} {test1} test1 {test2}",
[
"{test1}" => "two",
"{test2}" => "four",
"test1" => "three",
"test" => "one"
]
));
?>
this code would output:
string(22) "one two two three four"
Same output is generated even if you change the array items order:
<?php
var_dump(
strtr(
"test {test1} {test1} test1 {test2}",
[
"test" => "one",
"test1" => "three",
"{test1}" => "two",
"{test2}" => "four"
]
));
?>
string(22) "one two two three four"

Related

PHP - preg_replace on an array not working as expected

I have a PHP array that looks like this..
Array
(
[0] => post: 746
[1] => post: 2
[2] => post: 84
)
I am trying to remove the post: from each item in the array and return one that looks like this...
Array
(
[0] => 746
[1] => 2
[2] => 84
)
I have attempted to use preg_replace like this...
$array = preg_replace('/^post: *([0-9]+)/', $array );
print_r($array);
But this is not working for me, how should I be doing this?
You've missed the second argument of preg_replace function, which is with what should replace the match, also your regex has small problem, here is the fixed version:
preg_replace('/^post:\s*([0-9]+)$/', '$1', $array );
Demo: https://3v4l.org/64fO6
You don't have a pattern for the replacement, or a empty string place holder.
mixed preg_replace ( mixed $pattern , mixed $replacement , mixed $subject)
Is what you are trying to do (there are other args, but they are optional).
$array = preg_replace('/post: /', '', $array );
Should do it.
<?php
$array=array("post: 746",
"post: 2",
"post: 84");
$array = preg_replace('/^post: /', '', $array );
print_r($array);
?>
Array
(
[0] => 746
[1] => 2
[2] => 84
)
You could do this without using a regex using array_map and substr to check the prefix and return the string without the prefix:
$items = [
"post: 674",
"post: 2",
"post: 84",
];
$result = array_map(function($x){
$prefix = "post: ";
if (substr($x, 0, strlen($prefix)) == $prefix) {
return substr($x, strlen($prefix));
}
return $x;
}, $items);
print_r($result);
Result:
Array
(
[0] => 674
[1] => 2
[2] => 84
)
There are many ways to do this that don't involve regular expressions, which are really not needed for breaking up a simple string like this.
For example:
<?php
$input = Array( 'post: 746', 'post: 2', 'post: 84');
$output = array_map(function ($n) {
$o = explode(': ', $n);
return (int)$o[1];
}, $input);
var_dump($output);
And here's another one that is probably even faster:
<?php
$input = Array( 'post: 746', 'post: 2', 'post: 84');
$output = array_map(function ($n) {
return (int)substr($n, strpos($n, ':')+1);
}, $input);
var_dump($output);
If you don't need integers in the output just remove the cast to int.
Or just use str_replace, which in many cases like this is a drop in replacement for preg_replace.
<?php
$input = Array( 'post: 746', 'post: 2', 'post: 84');
$output = str_replace('post: ', '', $input);
var_dump($output);
You can use array_map() to iterate the array then strip out any non-digital characters via filter_var() with FILTER_SANITIZE_NUMBER_INT or trim() with a "character mask" containing the six undesired characters.
You can also let preg_replace() do the iterating for you. Using preg_replace() offers the most brief syntax, but regular expressions are often slower than non-preg_ techniques and it may be overkill for your seemingly simple task.
Codes: (Demo)
$array = ["post: 746", "post: 2", "post: 84"];
// remove all non-integer characters
var_export(array_map(function($v){return filter_var($v, FILTER_SANITIZE_NUMBER_INT);}, $array));
// only necessary if you have elements with non-"post: " AND non-integer substrings
var_export(preg_replace('~^post: ~', '', $array));
// I shuffled the character mask to prove order doesn't matter
var_export(array_map(function($v){return trim($v, ': opst');}, $array));
Output: (from each technique is the same)
array (
0 => '746',
1 => '2',
2 => '84',
)
p.s. If anyone is going to entertain the idea of using explode() to create an array of each element then store the second element of the array as the new desired string (and I wouldn't go to such trouble) be sure to:
split on or : (colon, space) or even post: (post, colon, space) because splitting on : (colon only) forces you to tidy up the second element's leading space and
use explode()'s 3rd parameter (limit) and set it to 2 because logically, you don't need more than two elements

str_replace is replacing on one line, but not on another

I am running into a strange issue. I have the following code:
$foo = array(
"some" => array(
"foo" => "boohoo",
"bar" => "foobar"
),
"really" => array(
"foo" => "boohoo",
"bar" => "barfoo"
),
"strange" => array(
"foo" => "boohoo",
"bar" => "foobarfoo"
),
"occurences" => array(
"foo" => "boohoo",
"bar" => "barbaz"
)
);
$page = "";
foreach($foo as $bar)
{
$subj = $template->loadTemplate('foobar', true);
$str = "";
$str = str_replace("{foo}", $bar['foo'], $subj);
$str = str_replace("{bar}", $bar['bar'], $subj);
$page .= $str;
}
The issue here is that when the PHP Code is run, {bar} is replaced in my template but not {foo}. I switched the two str_replace lines around and I got a different result -- {foo} is replaced but {bar} isn't! I've also tried swapping it for preg_replace and nothing changed. For the record, the $template->loadTemplate() function performs no operations on the string loaded, it simply gets the template from a file.
My questions are: why does PHP behave in this fashion, and second, how can I overcome this limitation/bug?
You changing only one, because use same input string for both replaces:
$str = str_replace("{foo}", $bar['foo'], $subj);
$str = str_replace("{bar}", $bar['bar'], $subj);
Try this:
$str = str_replace("{foo}", $bar['foo'], $subj);
$str = str_replace("{bar}", $bar['bar'], $str);
As said CORRUPT you are replacing the strings voiding the previous command.
I'd add that str_replace supports Array() as parameter.
$str = str_replace(Array("{foo}","{bar}"), Array($bar['foo'], $bar['bar']) , $subj);

Use of PHP explode() function

I have a problem, I want to split a string variable using the explode function but there are a limitation, imagine having the next string variable with the next value :
$data = "3, 18, 'My name is john, i like to play piano'";
Using the explode function : explode(",", $data), the output will be :
array(
[0] => 3,
[1] => 18,
[2] => 'My name is john,
[3] => i like to play piano'
);
My target is to split the variable $data by comma excluding the ones that are between ' ' chatacters.
e.g. array(
[0] => 3,
[1] => 18,
[2] => 'My name is john, i like to play piano'
);
If anyone can tell me a way to do this, I'd be grateful.
This looks rather like CSV data. You can use str_getcsv to parse this.
var_dump(str_getcsv("3, 18, 'My name is john, i like to play piano'", ',', "'"));
should result in:
array(3) {
[0] =>
string(1) "3"
[1] =>
string(3) " 18"
[2] =>
string(12) "My name is john, i like to play piano"
}
You may want to apply trim to each of the array elements too, by using array_map:
$string = "3, 18, 'My name is john, i like to play piano'";
var_dump(array_map('trim', str_getcsv($string, ',', "'")));
Use: str_getcsv
// set the delimiter with ',', and set enclosure with single quote
$arr = str_getcsv ($data, ',', "'");
You can use the str_getcsv() function as:
$data = "3, 18, 'My name is john, i like to play piano'";
$pieces = str_getcsv($data, ',', "'");
The first argument to the function is the string to be split.
The second argument is the delimiter on which you need to split.
And the third argument is the single character that when used as a pair (unsescaped) inside the first argument, will be treated as one field, effectively ignoring the delimiters between this pair.

PHP: preg_match and group repetition

How I can get all matched objects in a group using preg_match (or preg_match_all, maybe)?
For instance, I have ^(?:,?\s*(?<key>[a-z]))+$, if I apply to a, b, c, I get this:
object array
0 : string "a, b, c"
key: string "c"
1 : string "c"
I need basically of get a, b and c. Something like it (don't needly like it):
object array
0 : string "a, b, c"
key: object array
0 : string "a"
1 : string "b"
2 : string "c"
...
It's possible? What is the better solution? I need really to split it after match?
Split it on ,\s*, eg:
$array = preg_split("/,\\s*/", "a, b, c,d,e");
No you can not nest it like that. You can build the array manually however.
$str = 'a, b, c';
preg_match_all("/(\w),?/", $str, $m);
// create array
$a = array(
$str,
'key' => $m[1]
);
print_r($a);
You can use preg_split too go grab this elements.
$m = preg_split('/\W+/', $str, PREG_SPLIT_NO_EMPTY);

Convert Regexp in Js into PHP?

I have the following regular expression in javascript and i would like to have the exact same functionality (or similar) in php:
// -=> REGEXP - match "x bed" , "x or y bed":
var subject = query;
var myregexp1 = /(\d+) bed|(\d+) or (\d+) bed/img;
var match = myregexp1.exec(subject);
while (match != null){
if (match[1]) { "X => " + match[1]; }
else{ "X => " + match[2] + " AND Y => " + match[3]}
match = myregexp1.exec(subject);
}
This code searches a string for a pattern matching "x beds" or "x or y beds".
When a match is located, variable x and variable y are required for further processing.
QUESTION:
How do you construct this code snippet in php?
Any assistance appreciated guys...
You can use the regex unchanged. The PCRE syntax supports everything that Javascript does. Except the /g flag which isn't used in PHP. Instead you have preg_match_all which returns an array of results:
preg_match_all('/(\d+) bed|(\d+) or (\d+) bed/im', $subject, $matches,
PREG_SET_ORDER);
foreach ($matches as $match) {
PREG_SET_ORDER is the other trick here, and will keep the $match array similar to how you'd get it in Javascript.
I've found RosettaCode to be useful when answering these kinds of questions.
It shows how to do the same thing in various languages. Regex is just one example; they also have file io, sorting, all kinds of basic stuff.
You can use preg_match_all( $pattern, $subject, &$matches, $flags, $offset ), to run a regular expression over a string and then store all the matches to an array.
After running the regexp, all the matches can be found in the array you passed as third argument. You can then iterate trough these matches using foreach.
Without setting $flags, your array will have a structure like this:
$array[0] => array ( // An array of all strings that matched (e.g. "5 beds" or "8 or 9 beds" )
0 => "5 beds",
1 => "8 or 9 beds"
);
$array[1] => array ( // An array containing all the values between brackets (e.g. "8", or "9" )
0 => "5",
1 => "8",
2 => "9"
);
This behaviour isn't exactly the same, and I personally don't like it that much. To change the behaviour to a more "JavaScript-like"-one, set $flags to PREG_SET_ORDER. Your array will now have the same structure as in JavaScript.
$array[0] => array(
0 => "5 beds", // the full match
1 => "5", // the first value between brackets
);
$array[1] => array(
0 => "8 or 9 beds",
1 => "8",
2 => "9"
);

Categories