I have an string such as
$string = "This is my test string {ABC}. This is test {XYZ}. I am new for PHP {PHP}".
Now I need to replace occurrence of string within {}, in such a way that output will be:
This is my test string {ABC 1}. This is test {XYZ 2}. I am new for PHP {PHP 3}".
I am looking to resolve this with recursive function but not getting expected result.
$i = 1;
echo preg_replace_callback('/\{(.+?)\}/', function (array $match) use (&$i) {
return sprintf('{%s %d}', $match[1], $i++);
}, $string);
The "trick" is to simply keep an external counter running, here $i, which is used in the anonymous callback via use (&$i).
There is no recursion here. Simply counting.
$result = preg_replace_callback("/\{([^}]*+)\}/",function($m) {
static $count = 0;
$count++;
return "{".$m[1]." ".$count."}";
},$string);
If you really need recursive :^ )
$string = "This is my test string {ABC}. This is test {XYZ}. I am new for PHP {PHP}";
function my_replace($string, $count = 1)
{
if ($string)
{
return preg_replace_callback('/\{(.+?)\}(.*)$/', function (array $match) use ($count)
{
return sprintf('{%s %d} %s', $match[1], $count, my_replace($match[2], $count + 1));
}, $string, 1);
}
}
echo my_replace($string);
Related
I'm facing an issue with a function that gets a string between two other strings.
function string_between($str, $starting_word, $ending_word) {
$subtring_start = strpos($str, $starting_word);
$subtring_start += strlen($starting_word);
foreach ($ending_word as $a){
$size = strpos($str, $a, $subtring_start) - $subtring_start;
}
return substr($str, $subtring_start, $size);
}
The issue is that the function searches for the first ending_word in the array.
An example will be easier to understand:
$array_a = ['the', 'amen']; // Starting strings
$array_b = [',', '.']; // Ending strings
$str = "Hello, the world. Then, it is over.";
Expected result:
"the world."
Current result:
"the world. Then,"
The function will think that the ending_word is "," because it is the first element met in the array_b. However, the text encounters first the '.' after the "the" starting word.
How can I make sure the function goes through the text and stops at the first element in the $str present in the array_b, whatever the position in the array?
Any idea?
Basically, you need to break outside of your foreach loop when $size > 0
That way it stops looping through your array when it finds the 1st occurrence. Here is the more complete code with other fixes:
function stringBetween($string, $startingWords, $endingWords) {
foreach ($startingWords as $startingWord) {
$subtringStart = strpos($string, $startingWord);
if ($subtringStart > 0) {
foreach ($endingWords as $endingWord){
$size = strpos($string, $endingWord, $subtringStart) - $subtringStart + strlen($endingWord);
if ($size > 0) {
break;
}
}
if ($size > 0) {
return substr($string, $subtringStart, $size);
}
}
}
return null;
}
$startArr = array('the', 'amen'); // Starting strings
$endArr = array('.', ','); // Ending strings
$str = "Hello, the world. Then, it is over.";
echo stringBetween($str, $startArr, $endArr); // the world.
This type of problems are best solved by PCRE regexes, only couple of lines needed in function :
function string_between($str, $starts, $ends) {
preg_match("/(?:{$starts}).*?(?:{$ends})/mi", $str, $m);
return $m[0];
}
Then calling like this :
echo string_between("Hello, the world. Then, it is over.", 'the|amen', ',|\.');
Produces : the world.
The trick,- search to the nearest matching ending symbol is done with regex non-greedy seach, indicated by question symbol in pattern .*?. You can even extend this function to accept arrays as starting/ending symbols, just that case modify function (possibly with implode('|',$arr)) for concatenating symbols into regex grouping formula.
Edited version
This works now. Iterate over your teststrings from first array looking for position of occurance from teststring. If found one then search for the second teststring at startposition from end of first string.
To get the shortest hit I store the position from the second and take the minimum.
You can try it at http://sandbox.onlinephpfunctions.com/code/0f1e5c97da62b4daaf0e49f52271fe288d1cacbb
$array_a =array('the','amen');
$array_b =array(',','.', '#');
$str = "Hello, the world. Then, it is over.";
function earchString($str, $array_a, $array_b) {
forEach($array_a as $test) {
$pos = strpos($str, $test);
if ($pos===false) continue;
$found = [];
forEach($array_b 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 '';
}
echo earchString($str, $array_a, $array_b);
I am looking for a function or class that substitutes given string and returns array of all possible replacements.
In other words I am seeking for a magic_function:
function magic_function( $str, $find, $replace )
{
$arr = array();
// some magic stuff
return $arr;
}
var_dump( magic_function( 'aaa', 'a', 'b' ) );
/*
should return:
Array(
'aab',
'aba',
'baa',
'bba',
'bab',
'abb',
'bbb'
);
*/
I am thinking of using explode and then somehow looping through that array, but maybe there is a simpler way? Maybe with regex? Any ideas? :)
Thank you in advance!
explode and loop seems fairly simple.
<?php
function magic_function ($str, $find, $replace) {
$parts = explode($find, $str);
$n = count($parts)-1;
$p = 1<<$n;
for ($i=1; $i<$p; $i++) {
for ($perm="", $seps=$i, $j=0; $j<$n; $seps>>=1, $j++) {
$perm .= $parts[$j] . ($seps&1 ? $replace : $find);
}
$res[] = $perm . $parts[$n];
}
return $res;
}
Start from $i=0 to include the no-replacement case.
I want to add number from my string. this is my string
$formula = 'IF(B15="","",IF(ISNUMBER(A14),A14+1,IF(ISNUMBER(B3),B3+1,1)))';
i want add number if before the number is alphabet. for example i want to make B15 to B16 ini my string.. this my loop
$jum = strlen($formula);
for($i = 0; $i < $jum; $i++){
if(ctype_alpha($formula[$i]) && ctype_alnum($formula[$i+1])){
$temp_formula[$i+1] += 1;
}
}
You can do this with preg_replace_callback. Use this regex, which looks for a symbol of the form <letter><digits> between word boundaries:
\b([A-Z])(\d+)\b
and then in the callback the second group's value can be incremented:
$formula = 'IF(B15="","",IF(ISNUMBER(A14),A14+1,IF(ISNUMBER(B3),B3+1,1)))';
echo preg_replace_callback('/\b([A-Z])(\d+)\b/', function ($m) {
return $m[1] . (1 + $m[2]);
}, $formula);
Output:
IF(B16="","",IF(ISNUMBER(A15),A15+1,IF(ISNUMBER(B4),B4+1,1)))
Demo on 3v4l.org
Update
To use an external variable in the callback (as described in the comments), edit the code like this:
$formula = 'IF(B15="","",IF(ISNUMBER(A14),A14+1,IF(ISNUMBER(B3),B3+1,1)))';
$tambah = $adding + ($rekord*$highest);
echo preg_replace_callback('/\b([A-Z])(\d+)\b/', function ($m) use ($tambah) {
return $m[1] . ($tambah + $m[2]);
}, $formula);
I'm looking for a way to replace all but first occurrences of a group or some character.
For example a following random string:
+Z1A124B555ND124AB+A555
1,5,2,4,A,B and + are repeating through out the string.
124, 555 are groups of characters that are also reoccurring.
Now, let's say I want to remove every but first occurrence of 555, A and B.
What regex would be appropriate? I could think of an example replacing all:
preg_replace('/555|A|B/','',$string);
Something like ^ that, but I want to keep the first occurrence... Any ideas?
Are your strings always delimited by plus signs? Do 555, A, and B always occur in the first "group" (delimited by +)?
If so, you can split, replace and then join:
$input = '+Z1A124B555+A124AB+A555';
$array = explode('+', $input, 3); // max 3 elements
$array[2] = str_replace(array('555', 'A', 'B'), '', $array[2]);
$output = implode('+', $array);
ps. No need to use regexes, when we can use a simple str_replace
Use the preg_replace_callback function:
$replaced = array('555' => 0, 'A' => 0, 'B' => 0);
$input = '+Z1A124B555+A124AB+A555';
$output = preg_replace_callback('/555|[AB]/', function($matches) {
static $replaced = 0;
if($replaced++ == 0) return $matches[0];
return '';
}, $input);
This solution could be modified to do what you want: PHP: preg_replace (x) occurrence?
Here is a modified solution for you:
<?php
class Parser {
private $i;
public function parse($source) {
$this->i=array();
return preg_replace_callback('/555|A|B/', array($this, 'on_match'), $source);
}
private function on_match($m) {
$first=$m[0];
if(!isset($this->i[$first]))
{
echo "I'm HERE";
$this->i[$first]=1;
}
else
{
$this->i[$first]++;
}
// Return what you want the replacement to be.
if($this->i[$first]>1)
{
$result="";
}
else
{
$result=$m[0];
}
return $result;
}
}
$sample = '+Z1A124B555ND124AB+A555';
$parse = new Parser();
$result = $parse->parse($sample);
echo "Result is: [$result]\n";
?>
A more generic function that works with every pattern.
function replaceAllButFirst($pattern, $replacement, $subject) {
return preg_replace_callback($pattern,
function($matches) use ($replacement, $subject) {
static $s;
$s++;
return ($s <= 1) ? $matches[0] : $replacement;
},
$subject
);
}
Can someone help me with algorithm for finding the position of the first occurrence of any number in a string?
The code I found on the web does not work:
function my_offset($text){
preg_match('/^[^\-]*-\D*/', $text, $m);
return strlen($m[0]);
}
echo my_offset('[HorribleSubs] Bleach - 311 [720p].mkv');
The built-in PHP function strcspn() will do the same as the function in Stanislav Shabalin's answer when used like so:
strcspn( $str , '0123456789' )
Examples:
echo strcspn( 'That will be $2.95 with a coupon.' , '0123456789' ); // 14
echo strcspn( '12 people said yes' , '0123456789' ); // 0
echo strcspn( 'You are number one!' , '0123456789' ); // 19
HTH
function my_offset($text) {
preg_match('/\d/', $text, $m, PREG_OFFSET_CAPTURE);
if (sizeof($m))
return $m[0][1]; // 24 in your example
// return anything you need for the case when there's no numbers in the string
return strlen($text);
}
function my_ofset($text){
preg_match('/^\D*(?=\d)/', $text, $m);
return isset($m[0]) ? strlen($m[0]) : false;
}
should work for this. The original code required a - to come before the first number, perhaps that was the problem?
I can do regular expressions but I have to go into an altered state to
remember what it does after I've coded it.
Here is a simple PHP function you can use...
function findFirstNum($myString) {
$slength = strlen($myString);
for ($index = 0; $index < $slength; $index++)
{
$char = substr($myString, $index, 1);
if (is_numeric($char))
{
return $index;
}
}
return 0; //no numbers found
}
Problem
Find the first occurring number in a string
Solution
Here is a non regex solution in javascript
var findFirstNum = function(str) {
let i = 0;
let result = "";
let value;
while (i<str.length) {
if(!isNaN(parseInt(str[i]))) {
if (str[i-1] === "-") {
result = "-";
}
while (!isNaN(parseInt(str[i])) && i<str.length) {
result = result + str[i];
i++;
}
break;
}
i++;
}
return parseInt(result);
};
Example Input
findFirstNum("words and -987 555");
Output
-987