Skip to content
Advertisement

Using preg_replace to reformat money amounts in text with PHP

I’m struggling with some regular expressions. What I want to do is find money amounts in a string, remove the €,$, or £ but keep the number, and then look to see if there is a ‘b’ or an ‘m’ – in which case write ‘million platinum coins’ or ‘million gold coin’ respectively but otherwise just put ‘gold coins’.

I have most of that as a hack (see below) with the small problem that my regex does not seem to work. The money amount comes out unchanged.

Desired behaviour examples

I intend to leave the decimal places and thousands separators as is

$12.6m ==> 12.6 million gold coins

£2b ==> 2 million platinum coins

€99 ==> 99 gold coins

My code

Here is my non-working code (I suspect my regex might be wrong).

protected function funnymoney($text){
    $text = preg_replace('/[€$£]*([0-9.,]+)([mb])/i',' %1%',$text);
    $text = str_replace('%b%','million platnum coins',$text);
    $text = str_replace('%m%','million gold coins',$text);
    $text = str_replace('%%','gold coins',$text);
    return $text;
}

I would greatly appreciate it if someone could explain to me what I am missing or getting wrong and guide me to the right answer. You may safely assume I know very little about regular expressions. I would like to understand why the solution works too if I can.

Advertisement

Answer

I am not sure how you intend to handle decimal places and thousands separators, so that part of my pattern may require adjustment. Beyond that, match the leading currency symbol (so that it is consumed/removed, then capture the numeric substring, then capture the optional trailing units (b or m).

Use a lookup array to translate the units to English. When the unit character is missing, apply the fallback value from the lookup array.

A lookup array will make your task easier to read and maintain.

Code: (Demo)

$str = '$1.1m
Foo
£2,2b
Bar
€99.9';

$lookup = [
    'b' => 'million platinum coins',
    'm' => 'million gold coins',
    ''  => 'gold coins',
];

echo preg_replace_callback(
         '~[$£€](d+(?:[.,]d+)?)([bm]?)~iu',
         function($m) use ($lookup) {
             return "$m[1] " . $lookup[strtolower($m[2])];
         },
         $str
     );

Output:

1.1 million gold coins
Foo
2,2 million platinum coins
Bar
99.9 gold coins
User contributions licensed under: CC BY-SA
6 People found this is helpful
Advertisement