Regex to transform abcd to (a(b(c(d)))) - php

I'm using PHP's preg_replace, and trying to transform the string
abcd
into
(a(b(c(d))))
This is the best I've got:
preg_replace('/.(?=(.*$))/', '$0($1)', 'abcd');
// a(bcd)b(cd)c(d)d()
Is it even possible with regex?
Edit I've just discovered this in the PCRE spec: Replacements are not subject to re-matching, so my original approach isn't going to work. I wanted to keep it all regex because there's some more complicated matching logic in my actual use case.

How about:
preg_replace('/./s', '($0', 'abcd') . str_repeat(')', strlen('abcd'));
?
(Does that count as "with regex"?)

You can use preg_match_all. Not sure what kind of characters you want, though. So I'll give an example for all characters:
$val = 'abcd1234';
$out = '';
if(preg_match_all('#.#', $val, $matches))
{
$i = 0; // we'll use this to keep track of how many open paranthesis' we have
foreach($matches[0] as &$v)
{
$out .= '('.$v;
$i++;
}
$out .= str_repeat(")", $i);
}
else
{
// no matches found or error occured
}
echo $out; // (a(b(c(d(1(2(3(4))))))))
Will be easy to customise further, as well.

This is my way to do it =) :
<?php
$arr = str_split("abcd");
$new_arr = array_reverse($arr);
foreach ($new_arr as $a) {
$str = sprintf('(%s%s)', $a, $str);
}
echo "$str\n";
?>
KISS isn't it ? (few lines : 6)

I went with something along the lines of a combination of the above answers:
preg_match_all('/./ui', 'abcd', $matches);
$matches = $matches[0];
$string = '('.implode('(', $matches).str_repeat(')', count($matches));

Related

How to find ALL substrings in string using starting and ending words arrays PHP

I've spent my last 4 hours figuring out how to ... I got to ask for your help now.
I'm trying to extract from a text multiple substring match my starting_words_array and ending_words_array.
$str = "Do you see that ? Indeed, I can see that, as well as this." ;
$starting_words_array = array('do','I');
$ending_words_array = array('?',',');
expected output : array ([0] => 'Do you see that ?' [1] => 'I can see that,')
I manage to write a first function that can find the first substring matching one of both arrays items. But i'm not able to find how to loop it in order to get all the substring matching my requirement.
function SearchString($str, $starting_words_array, $ending_words_array ) {
forEach($starting_words_array as $test) {
$pos = strpos($str, $test);
if ($pos===false) continue;
$found = [];
forEach($ending_words_array as $test2) {
$posStart = $pos+strlen($test);
$pos2 = strpos($str, $test2, $posStart);
$found[] = ($pos2!==false) ? $pos2 : INF;
}
$min = min($found);
if ($min !== INF)
return substr($str,$pos,$min-$pos) .$str[$min];
}
return '';
}
Do you guys have any idea about how to achieve such thing ?
I use preg_match for my solution. However, the start and end strings must be escaped with preg_quote. Without that, the solution will be wrong.
function searchString($str, $starting_words_array, $ending_words_array ) {
$resArr = [];
forEach($starting_words_array as $i => $start) {
$end = $ending_words_array[$i] ?? "";
$regEx = '~'.preg_quote($start,"~").".*".preg_quote($end,"~").'~iu';
if(preg_match_all($regEx,$str,$match)){
$resArr[] = $match[0];
}
}
return $resArr;
}
The result is what the questioner expects.
If the expressions can occur more than once, preg_match_all must also be used. The regex must be modify.
function searchString($str, $starting_words_array, $ending_words_array ) {
$resArr = [];
forEach($starting_words_array as $i => $start) {
$end = $ending_words_array[$i] ?? "";
$regEx = '~'.preg_quote($start,"~").".*?".preg_quote($end,"~").'~iu';
if(preg_match_all($regEx,$str,$match)){
$resArr = array_merge($resArr,$match[0]);
}
}
return $resArr;
}
The resut for the second variant:
array (
0 => "Do you see that ?",
1 => "Indeed,",
2 => "I can see that,",
)
I would definitely use regex and preg_match_all(). I won't give you a full working code example here but I will outline the necessary steps.
First, build a regex from your start-end-pairs like that:
$parts = array_map(
function($start, $end) {
return $start . '.+' . $end;
},
$starting_words_array,
$ending_words_array
);
$regex = '/' . join('|', $parts) . '/i';
The /i part means case insensitive search. Some characters like the ? have a special purpose in regex, so you need to extend above function in order to escape it properly.
You can test your final regex here
Then use preg_match_all() to extract your substrings:
preg_match_all($regex, $str, $matches); // $matches is passed by reference, no need to declare it first
print_r($matches);
The exact structure of your $matches array will be slightly different from what you asked for but you will be able to extract your desired data from it
Benni answer is best way to go - but let just point out the problem in your code if you want to fix those:
strpos is not case sensitive and find also part of words so you need to changes your $starting_words_array = array('do','I'); to $starting_words_array = array('Do','I ');
When finding a substring you use return which exit the function so you want find any other substring. In order to fix that you can define $res = []; at the beginning of the function and replace return substr($str,$pos,... with $res[] = substr($str,$pos,... and at the end return the $res var.
You can see example in 3v4l - in that example you get the output you wanted

PHP get words with length longer than 3 from string

Is there a function that can cut words from a string that are small length e.g. "the, and, you, me, or" all these short words that are common in all sentences. i want to use this function to fill a fulltext search with criteria
before the method:
$fulltext = "there is ongoing work on creating a formal PHP specification.";
outcome:
$fulltext_method_solution = "there ongoing work creating formal specification."
$fulltext = "there is ongoing work on creating a formal PHP specification.";
$words = array_filter(explode(' ', $fulltext), function($val){
return strlen($val) > 3; // filter words having length > 3 in array
});
$fulltext_method_solution = implode(' ', $words); // join words into sentence
try this:
$fulltext = "there is ongoing work on creating a formal PHP specification.";
$result=array();
$array=explode(" ",$fulltext);
foreach($array as $key=>$val){
if(strlen($val) >3)
$result[]=$val;
}
$res=implode(" ",$result);
You can simply use implode, explode along with array_filter
echo implode(' ',array_filter(explode(' ',$fulltext),function($v){ return strlen($v) > 3;}));
or simply use preg_replace as
echo preg_replace('/\b[a-z]{1,3}\b/i','',$fulltext);
try this:
$stringArray = explode(" ", $fulltext);
foreach ($stringArray as $value)
{
if(strlen($value) < 3)
$fulltext= str_replace(" ".$value." " ," ",$fulltext);
}
Here is a working DEMO
Simply explode the string and check for the strlen()
$fulltext = "there is ongoing work on creating a formal PHP specification.";
$ex = explode(' ',$fulltext);
$res = '';
foreach ($ex as $txt) {
if (strlen($txt) > 3) {
$res .= $txt . ' ';
}
}
echo $res;
By using preg_replace
echo $string = preg_replace(array('/\b\w{1,3}\b/','/\s+/'),array('',' '),$fulltext);
This will also produce the desired results:
<?php
$fulltext = "there is ongoing work on creating a formal PHP specification.";
$fulltext = preg_replace('/(\b.{1,3}\s)/',' ',$fulltext);
echo $fulltext;
?>

replacing letters with numbers

So i've been trying to get this bit of code to work all day and haven't been able to do it... I wnat to be able to replace letters with a number (or just a value) from an array. this is the code i've got:
$l2n =
array(
'a'=>'1',
'b'=>'2',
'c'=>'3',
'd'=>'4',
'e'=>'5',
'f'=>6,
'g'=>7,
'h'=>8,
'i'=>9,
'j'=>10,
'k'=>11,
'l'=>12,
'm'=>13,
'n'=>14,
'o'=>15,
'p'=>16,
'q'=>17,
'r'=>18,
's'=>19,
't'=>20,
'u'=>21,
'v'=>22,
'w'=>23,
'x'=>24,
'y'=>25,
'z'=>16
);
$string = str_split($string);
$explode = array_shift($string);
if($l2n[$explode] == $explode)
{
echo $l2n[$explode];
}
else
{
echo $l2n['a'];
}
I tried to use Preg_replace but i've never had a good expereince with that function. so If anybody could help me out, hint me in the correct direction, that'd be great.
You can just use str_replace once you've used array_keys and array_values to get each side of the array:
$keys = array_keys($l2n);
$values = array_values($l2n);
$yourstring = 'Hello world!';
echo str_replace($keys, $values, $yourstring);
// H5121215 231518124!
Demo: https://eval.in/77453
Docs:
http://php.net/str_replace
http://php.net/array_keys
http://php.net/array_values
You can simply do:
$string = preg_replace(array_keys($l2n), array_values($l2n), $string);
From the documentation:
If both pattern and replacement parameters are arrays, each pattern will be replaced by the replacement counterpart.
Why in the world would you use an array for this? Isn't ord() what you are looking for here?
$string = "ABCDE";
foreach ( str_split($string) as $chr ) {
echo ord($chr) - 64; // or 97 if they all are lowercase
echo PHP_EOL;
}

how to parse str in variable

I am trying to parse following text in variable...
$str = 3,283,518(10,569 / 2,173)
And i am using following code to get 3,283,518
$arr = explode('(',$str);
$num = str_replace(',','',$arr[0]); //prints 3283518
the above $str is dynamic and sometimes it could be only 3,283,518(means w/o ()) so explode function will throw an error so what is the best way to get this value? thanks.
$str = "3,283,518(10,569 / 2,173)";
preg_match("/[0-9,]+/", $str, $res);
$match = str_replace(",", "", array_pop($res));
print $match;
This will return 3283518, simply by taking the first part of the string $str that only consists of numbers and commas. This would also work for just 3,283,518 or 3,283,518*10,569, etc.
Probably going to need more information from you about how dynamic $str really is but if its just between those values you could probably do the following
if (strpos($str, '(' ) !== false) {
$arr = explode('(',$str);
$num = str_replace(',','',$arr[0]);
} else {
//who knows what you want to do here.
}
If you are really sure about number format, you can try something like:
^([0-9]+,)*([0-9]+)
Use it with preg_match for example.
But if it is not a simple format, you should go with an arithmetic expressions parser.
Analog solution:
<?php
$str = '3,283,518(10,569 / 2,173)';
if (strstr($str, '('))
{
$arr = explode('(',$str);
$num = str_replace(',','',$arr[0]);
}
else
{
$num = str_replace(',','',$str);
}
echo $num;
?>

php preg_match problem

how can i get 41P86246HOH7C1G4A983321910HDL63U9 from the following with preg_match
input type="text" value="41P86246HOH7C1G4A983321910HDL63U9" id=""
DOMDocument::loadHTML("<$input>")->getElementsByTagName('input')
->item(0)->getAttribute('value');
What about something like this :
$str = 'input type="text" value="41P86246HOH7C1G4A983321910HDL63U9" id=""';
$m = array();
if (preg_match('#value="([^"]+)"#', $str, $m)) {
var_dump($m[1]);
}
Which will match everything between the double quotes that come with value, and get you :
string '41P86246HOH7C1G4A983321910HDL63U9' (length=33)
But, as a sidenote : if you are trying to "parse" HTML with regex, it's generally not the "best" way ; HTML is not quite regular enough for regex...
Simply, without extra characters:
preg_match('/(?<=value=")[0-9A-Za-z]+/', $str, $match);
Your result is in $match[0];
With something like this:
if(preg_match('#value="([^"]*)"#', $text, $m)){
echo $m[1];
}
But you can also make something who split the string in each key with this value.
function attributes($text){
$attrs = array();
if(preg_match_all('#(\b[^=]*\b)\s*=\s*"([^"]+)"#', $text, $matches, PREG_SET_ORDER)){
foreach($matches as $m){
$attrs[$m[1]] = $m[2];
}
}
return $attrs;
}
// Use like this
$attrs = attributes('input value="bla"');
if(isset($attrs['value'])){
echo $attrs['value'];
}
don't even have to use regex. Just use PHP's string methods
$str='input type="text" value="41P86246HOH7C1G4A983321910HDL63U9" id=""';
$s = explode(" ",$str);
// go through each element, find "value"
foreach($s as $a=>$b){
if(strpos($b,"value")!==FALSE){
$find = explode("=",$b);
print $find[1];
}
}

Categories