PHP: preg_match and group repetition - php

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);

Related

String by string replacement

i got an array
$array = [
"a" => "c",
"b" => "d",
"c" => "a",
"d" => "b",
];
and a string $text = "dcab";
How can i replace with my array elements each letter on my string, im try to figure out by steps but not luck,
1.- explode my string
2.- for each letter str_replace,
output will be: bacd
thank for help.
Well you can't use str_replace() because of the big warning that it shows in the documentation:
Replacement order gotcha
Because str_replace() replaces left to right, it might replace a previously inserted value when doing multiple replacements. See also the examples in this document.
Then take a look at the strtr() function
echo strtr($text, $array);

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

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"

Parse string of alternating letters and numbers (no delimiters) to associative array

I need to parse a string of alternating letters and number and populate an array where the letters are the keys and the numbers are the values.
Example:
p10s2z1234
Output
Array(
'p' => 10,
's' => 2,
'z' => 1234
)
Use regex to get desired values and then combine arrays to get associative array. For example:
$str = 'p10s2z1234';
preg_match_all('/([a-z]+)(\d+)/', $str, $matches); //handles only lower case chars. feel free to extend regex
print_r(array_combine($matches[1], $matches[2]));
Scenario 1: You want to parse the string which has single letters to be keys, will produce three pairs of values, and you want the digits to be cast as integers. Then the best, most direct approach is sscanf() with array destructuring -- a single function call does it all. (Demo)
$str = 'p10s2z1234';
[
$k1,
$result[$k1],
$k2,
$result[$k2],
$k3,
$result[$k3]
] = sscanf($str, '%1s%d%1s%d%1s%d');
var_export($result);
Output:
array (
'p' => 10,
's' => 2,
'z' => 1234,
)
Scenario 2: You want the same parsing and output as scenario 1, but the substrings to be keys have variable/unknown length. (Demo)
$str = 'pie10sky2zebra1234';
[
$k1,
$result[$k1],
$k2,
$result[$k2],
$k3,
$result[$k3]
] = sscanf($str, '%[^0-9]%d%[^0-9]%d%[^0-9]%d');
var_export($result);
Scenario 3: You want to parse the string with regex and don't care that the values are "string" data-typed. (Demo)
$str = 'pie10sky2zebra1234';
[
$k1,
$result[$k1],
$k2,
$result[$k2],
$k3,
$result[$k3]
] = preg_split('/(\d+)/', $str, 0, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE);
var_export($result);
Scenario 4: If you don't know how many pairs will be generated by the input string, use array_combine(). (Demo)
$str = 'pie10sky2zebra1234extra999';
var_export(
preg_match_all('/(\D+)(\d+)/', $str, $m)
? array_combine($m[1], $m[2])
: []
);

replace different sub strings in a string

I want to replace different sub-strings with multiple different strings in a string, is there a nicer way to do rather than i do labor work and use
str_replace ( mixed $search , mixed $replace , mixed $subject [, int &$count ] )
as many times as the number of strings to be replaced?
for example: replace a, b and c with d, e and f respectively in any sample string.
Of course i have a large number of words to change for this i need it.
str_replace() accepts an array for both search and replace parameters, so you can pass several strings in array to search and will be replaced by the corresponding strings in the array passed in replace parameter, like so:
$search = array('a','b','c');
$replace = array('d','e','f');
$res = str_replace($search, $replace, 'a b cool');
echo $res; //echoes 'd e fool'
The usual way of doing this is to supply an array of translations
$xlat = array(
'a' => 'd',
'b' => 'e',
'c' => 'f',
);
and then pass it to str_replace:
$result = str_replace(array_keys($xlat), array_values($xlat), $source);
You can build the array from a SQL query or other source.
You must be careful in case there is an intersection between the source and replacement string sets, or internal matches between source strings, e.g.
'Alpha' => 'Beta',
'Beta' => 'Gamma',
or even more sneaky,
'Alpha' => 'Beta',
'Alphabet' => 'ABCDEFGHIJ',
because internally str_replace employs a loop, and therefore "Base Alpha" would come out as "Base Gamma", and "Alphabet" as "Betabet" instead of "ABCDEFGHIJ". One possible way of coping with this is build $xlat incrementally; if you find that in the new couple 'a' => 'b', 'a' is already in the values of $xlat, you can push it onto $xlat instead of appending. Of course, more complicated sets of keywords (or even the exchange of two or more terms) might not be solvable.
Another way is to do it in two runs: you first generate a $xlat1 array of the form
'a' => '###<UNIQUEID1>###',
'b' => '###<UNIQUEID2>###',
and a second array of the form
'###<UNIQUEID1>###' => 'c',
'###<UNIQUEID2>###' => 'd',
You may "upgrade" the first one-array form to the second with a loop:
// First step, we sort $xlat in order of decreasing key size.
// This ensures that *Alphabet* will be replaced before *Alpha* is ever checked.
// Then we build
foreach($xlat as $from => $to)
{
$id = uniqid();
$xlat1[$from] = $id;
$xlat2[$id] = $to;
}
$temp = str_replace(array_keys($xlat1), array_values($xlat1), $source);
$result = str_replace(array_keys($xlat2), array_values($xlat2), $temp);

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