1

I have a string which contains certain number of #{number} structures. For example:

#328_#918_#1358
SKU:#666:#456
TEST--#888/#982

For each #{number} structure, I have to replace it with a known string.

For the first example:
#328_#918_#1358
I have the following strings:

328="foo"
918="bar"
1358"arg"

And the result should be:
foo_bar_arg

How do I achieve such effect? My current code looks like that:

$matches = array();
$replacements = array();
// starting string
$string = "#328_#918:#1358";
// getting all the numbers from the string
preg_match_all("/\#[0-9]+/", $string, $matches);
// getting rid of #
foreach ($matches[0] as $key => &$feature) {
    $feature = preg_replace("/#/", "", $feature);
} // end foreach
// obtaining the replacement values
foreach ($matches[0] as $key => $value) {
    $replacement[$value] = "fizz"; // here the value required for replacement is obtained
} // end foreach

But I have no idea how to actually perform a replacement in $string variable using values from $replacement table. Any help is much appreciated!

5
  • Where are your replacement rules stored (e.g. 328="foo")? Commented Apr 16, 2021 at 10:10
  • Does it matter? Let's say that after I get the numbers from the string, I can easily obtain them. Obtaining replacement values is not a problem, putting them into the string is an issue. Commented Apr 16, 2021 at 10:11
  • 2
    I'm asking because if you have them all in an array, then strtr would be a viable solution. Commented Apr 16, 2021 at 10:16
  • What should happen if for example #328 is #3289? Commented Apr 16, 2021 at 10:18
  • Yes, they are in array $replacement. Solution below works for me, but strtr() is also viable, thank you :) Commented Apr 16, 2021 at 10:19

1 Answer 1

1

You can use a preg_replace_callback solution:

$string = '#328_#918:#1358
SKU:#666:#456
TEST--#888/#982';
$replacements = [328=>"foo", 918=>"bar", 1358=>"arg"];
echo preg_replace_callback("/#([0-9]+)/", function ($m) use ($replacements) {
    return isset($replacements[$m[1]]) ? $replacements[$m[1]] : $m[0];
}
,$string);

See the PHP demo.

The #([0-9]+) regex will match all non-overlapping occurrences of # and one or more digits right after capturing them into Group 1. If there is an item in the replacements associative array with the numeric key, the whole match is replaced with the corresponding value. Else, the match is returned so that no replacement could occur and the match does not get removed.

Sign up to request clarification or add additional context in comments.

8 Comments

This method is more like "case sensitive" @MikaelDiak what about #3289 does it get it's assigned replacement or should it be "foo" and a 9 ? you should consider that question if the numbers should happen to be dynamic
@KevinGales That is not case sensitive, that is, #([0-9]+) will not allow partial matches, true. If that is not what is required, the regex can be formed with the array keys, $regex = '/#(' . implode("|",array_keys($replacements)) . ')/';. See this PHP demo.
By case sensitive in "" I mean this would replace #328_ but not #3289_ test it..
@KevinGales I think I got it right, I just want to say that digit chars are case-free.
Do this... go to the live demo and change 328 to 3289 and see what I am talking about....maybe you'll understand what I am talking about
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.