How to solve € 25.99 vs € 25.99 preg_match problem?

If I have these lines:

$string1 = "This book costs €25.99 in our shop." 

and on the other hand

 $string2 = "This book costs 25,99€ in our shop." 

How to get "€ 25.99" or "25.99 €" using preg_match ? What does the code look like?

Please note that there are two ways to write the euro symbol. The correct way in the EU is to write the character after the number, for example, 25,99 € and use a comma as a desimal separator . However, many American people adhere to the dollar way (€ 25.99) and the point as a desimal separator .

How to perform this check for both cases and get the value with the symbol in the cleanest and most effective way?

+6
source share
3 answers

Here's the raw regular expression: €\d+(?:[,.]\d+)?|\d+(?:[,.]\d+)?€

 preg_match ( "/€\d+(?:[,.]\d+)?|\d+(?:[,.]\d+)?€/" , $string1, $matches) 

If you want to consider additional spaces between the euro and the value, use this:

 preg_match ( "/€ ?\d+(?:[,.]\d+)?|\d+(?:[,.]\d+)? ?€/" , $string1, $matches) 
+4
source
Template

agent-j is on the right track, but I would do something a little more restrictive:

 /€\d+(:?[.,]\d{2})?|\d+(:?[.,]\d{2})?€/ 

The only difference is that the decimal is limited to two places, if it exists. I don’t think you want to allow something like 99,999€ , especially since it can mean β€œ99 thousand, 999 euros” if they are written in American style.

What I think you are trying to find in your link to the cleanest and most effective way is that the above template seems uncomfortable and redundant when you look at it. Is this basically part of \d+(:?[.,]\d{2})? repeating twice with the cross sides of the symbol €. This seems wrong, but it is not. You cannot get around this without introducing as much complexity, if not more. Even if you try to get around this with fancy images, it will look something like this:

 /^(?=.*€)€?\d+(:?[.,]\d{2})?((?<!€.*)€)?$/ 

Obviously, this is not an improvement. Sometimes the most obvious solution is the best, even if it makes you feel dirty.

Note. If you want to go crazy with him, you can try the option (carefully: untested, and I did not do much PHP at that time):

 $inner = "(:?\d{1,3}(?:([.,])\d{3})*(?:(?!\1)[.,]\d{2})?|\d*(?:[.,]\d{2})?)"; 

Using:

 preg_match ( "/€" . $inner . "|" . $inner . "€/", $string1, $matches) 

This should also take things like 99,999,99; 999,999.99; 9.999.999.99; +0.99; and etc.

+2
source

Check both options:

 /([$€]?[\d,]+[$€]?)/ 

What? makes [$€] optional (literally "0 or 1 of ..."), so you will need to check the degenerate case where there is only a small number without a currency symbol.

0
source

Source: https://habr.com/ru/post/894317/


All Articles