Regular expression currency format with dots and comma - php

My goal is getting something like that: 150.000,54 or 48.876,05 which means my commas are decimal starters.
Here's my code so far :
<?php
//cut numbers after comma if there are any, after 2 digits
$matchPattern = '/[0-9]+(?:\,[0-9]{2}){0,2}/';
//remove everything except numbers, commas and dots
$repl1 = preg_replace("/[^a-zA-Z0-9,.]/", "", $input);
//let there be a 0 before comma to have values like 0,75
$repl2 = preg_replace("/^[0]{1}$/", "",$repl1);
//now i need you here to help me for the expression putting dots after each 3 numbers, until the comma:
$repl3 = preg_replace("/regexphere$/", ".", $repl2);
preg_match($matchPattern, $repl3, $matches);
echo($matches[0]);
?>
I know preg_replacing 3 times is stupid but I am not good at writing regular expressions. If you have a better idea, don't just share it but also explain. I know a little of the types : http://regexone.com/lesson/0
Thank you in advance.
--------UPDATE--------
So I need to handle 0000,45 like inputs to 0,45 and like 010101,84 inputs to 1,84
When this is done, I'm done.
$input = Input::get('userinput');
$repl1 = preg_replace("/[^0-9,.]/", "", $input);
$repl2 = preg_replace("/^0/", "",$repl1);
$repl3 = str_replace(".","",$repl2);
preg_match('/[0-9]+(?:\,[0-9]{2}){0,2}/', $repl3, $matches);
$repl4 = preg_replace('/(\d)(?=(\d{3})+(?!\d))/', '$1.', $matches[0]);
return repl4;
----UPDATE----
Here's what i get so far : https://ideone.com/5qmslB
I just need to remove the zeroes before the comma, before the numbers.

I am not sure this is the best way, but I hope it is helpful.
Here is the updated code that I used with a fake $input:
<?php
$input = "textmdwrhfejhg../,2222233333,34erw.re.ty";
//cut numbers after comma if there are any, after 2 digits
$matchPattern = '/[0-9]+(?:\,[0-9]{2}){0,2}/';
//remove everything except numbers, commas and dots
$repl1 = trim(preg_replace("/[^0-9,.]/", "", $input), ".,");
echo "$repl1" . "\n";
//let there be a 0 before comma to have values like 0,75, remove the 0
$repl2 = preg_replace("/^0/", "",$repl1);
echo "$repl2" . "\n";
//The expression putting dots after each 3 numbers, until the comma:
$repl3 = preg_replace('/(\d)(?=(?:\d{3})+(?!\d))/', '$1.', $repl2);
echo "$repl3" . "\n";
The expression putting dots after each 3 numbers is
(\d)(?=(?:\d{3})+(?!\d))
Here, you can see how it works. In plain human,
(\d) - A capturing group that we'll use in the replacement pattern, matching a single digit that....
(?=(?:\d{3})+(?!\d)) - is followed by groups of 3 digits. External (?=...) is a look-ahead construction that checks but does not consume characters, (?:\d{3})+ is a non-capturing group (no need to keep the matched text in memory) that matches 3 digits exactly (due to the limiting quantifier {3}) 1 or more times (due to the + quantifier), and (?!\d) is a negative look-ahead checking that the next character after the last matched 3-digit group is not a digit.
This does not work in case we have more than 3 digits after a decimal separator. With regex, I can only think of a way to support 4 digits after decimal with (?<!,)(\d)(?=(?:\d{3})+(?!\d)). Not sure if there is a generic way without variable-width look-behind in PHP (as here, we also need a variable-width look-ahead, too). Thus, you might consider splitting the $repl2 value by comma, and only pass the first part to the regex. Then, combine. Something like this:
$spl = split(',', $repl2); // $repl2 is 1234,123456
$repl3 = preg_replace('/(\d)(?=(?:\d{3})+(?!\d))/', '$1.', $spl[0]);
$repl3 .= "," . $spl[1]; // "1.234" + "," + "123456"
echo "$repl3" . "\n"; // 1.234,123456
Update:
The final code I have come up with:
$input = "textmdwrhfejhg../0005456,2222233333,34erw.re.ty";
//Here's mine :
$repl1 = trim(preg_replace("/[^0-9,.]/", "", $input), '.,');
//following line just removes one zero, i want it to remove all chars like
//Input : 000549,569 Output : 549,569
echo "$repl1\n";
$repl2 = preg_replace("/^0+(?!,)/", "",$repl1);
$repl3 = str_replace(".","",$repl2);
preg_match('/[0-9]+(?:\,[0-9]{2}){0,2}/', $repl3, $matches);
$repl4 = preg_replace('/(\d)(?=(\d{3})+(?!\d))/', '$1.', $matches[0]);
echo $repl4;

Related

How to replace all occurrences of a character except the first one in PHP using a regular expression?

Given an address stored as a single string with newlines delimiting its components like:
1 Street\nCity\nST\n12345
The goal would be to replace all newline characters except the first one with spaces in order to present it like:
1 Street
City ST 12345
I have tried methods like:
[$street, $rest] = explode("\n", $input, 2);
$output = "$street\n" . preg_replace('/\n+/', ' ', $rest);
I have been trying to achieve the same result using a one liner with a regular expression, but could not figure out how.
I would suggest not solving this with complicated regex but keeping it simple like below. You can split the string with a \n, pop out the first split and implode the rest with a space.
<?php
$input = explode("\n","1 Street\nCity\nST\n12345");
$input = array_shift($input) . PHP_EOL . implode(" ", $input);
echo $input;
Online Demo
You could use a regex trick here by reversing the string, and then replacing every occurrence of \n provided that we can lookahead and find at least one other \n:
$input = "1 Street\nCity\nST\n12345";
$output = strrev(preg_replace("/\n(?=.*\n)/", " ", strrev($input)));
echo $output;
This prints:
1 Street
City ST 12345
You can use a lookbehind pattern to ensure that the matching line is preceded with a newline character. Capture the line but not the trailing newline character and replace it with the same line but with a trailing space:
preg_replace('/(?<=\n)(.*)\n/', '$1 ', $input)
Demo: https://onlinephp.io/c/5bd6d
You can use an alternation pattern that matches either the first two lines or a newline character, capture the first two lines without the trailing newline character, and replace the match with what's captured and a space:
preg_replace('/(^.*\n.*)\n|\n/', '$1 ', $input)
Demo: https://onlinephp.io/c/2fb2f
I leave you another method, the regex is correct as long as the conditions are met, in this way it always works
$string=explode("/","1 Street\nCity\nST\n12345");
$string[0]."<br>";
$string[1]." ".$string[2]." ".$string[3]

Regex rules in an array

Maybe it can not be solved this issue as I want, but maybe you can help me guys.
I have a lot of malformed words in the name of my products.
Some of them has leading ( and trailing ) or maybe one of these, it is same for / and " signs.
What I do is that I am explode the name of the product by spaces, and examines these words.
So I want to replace them to nothing. But, a hard drive could be 40GB ATA 3.5" hard drive. I need to process all the word, but I can not use the same method for 3.5" as for () or // because this 3.5" is valid.
So I only need to replace the quotes, when it is at the start of the string AND at end of the string.
$cases = [
'(testone)',
'(testtwo',
'testthree)',
'/otherone/',
'/othertwo',
'otherthree/',
'"anotherone',
'anothertwo"',
'"anotherthree"',
];
$patterns = [
'/^\(/',
'/\)$/',
'~^/~',
'~/$~',
//Here is what I can not imagine, how to add the rule for `"`
];
$result = preg_replace($patterns, '', $cases);
This is works well, but can it be done in one regex_replace()? If yes, somebody can help me out the pattern(s) for the quotes?
Result for quotes should be this:
'"anotherone', //no quote at end leave the leading
'anothertwo"', //no quote at start leave the trailin
'anotherthree', //there are quotes on start and end so remove them.
You may use another approach: rather than define an array of patterns, use one single alternation based regex:
preg_replace('~^[(/]|[/)]$|^"(.*)"$~s', '$1', $s)
See the regex demo
Details:
^[(/] - a literal ( or / at the start of the string
| - or
[/)]$ - a literal ) or / at the end of the string
| - or
^"(.*)"$ - a " at the start of the string, then any 0+ characters (due to /s option, the . matches a linebreak sequence, too) that are captured into Group 1, and " at the end of the string.
The replacement pattern is $1 that is empty when the first 2 alternatives are matched, and contains Group 1 value if the 3rd alternative is matched.
Note: In case you need to replace until no match is found, use a preg_match with preg_replace together (see demo):
$s = '"/some text/"';
$re = '~^[(/]|[/)]$|^"(.*)"$~s';
$tmp = '';
while (preg_match($re, $s) && $tmp != $s) {
$tmp = $s;
$s = preg_replace($re, '$1', $s);
}
echo $s;
This works
preg_replace([[/(]?(.+)[/)]?|/\"(.+)\"/], '$1', $string)

Regex to remove xx. from the start of a string but only 2 digits (code half completed)

I'm trying to work out a quick and simple way to remove the first two digits and a decimal
from a string, if that is how it is made up.
I am half way there but need help to finish.
So (first is what I start with, 2nd is the result):
xx.yyy = yyy
aaaaa = aaaaa
test.hello = test.hello
a.test.b.x = a.test.b.x
aa.bb.cc = bb.cc
So it only removes 2 digits and a decimal if it exists like that. If it is three digits and a decimal then it isn't removed.
This is where I am so far:
$string = 'xx.hello';
$pattern = '/(2-digits)./i';
$replacement = ''; // remove if matched
echo preg_replace($pattern, $replacement, $string);
?>
This will do letters, digits, and underscores:
preg_replace('/^\w{2}\./', '', $string);
Without numbers or underscores, both upper and lowercase:
preg_replace('/^[a-zA-Z]{2}\./', '', $string);
Assuming by "digits" you mean actual digits (0-9) and by "decimal" a dot:
$string = preg_replace('/^\d{2}\./','',$string);
Try the following:
$pattern = "~^[0-9A-Za-z]{2}\\.~";
It matches two alphanumerical characters at the beginning of the string, followed by a period (.). Notice that the period has been escaped so the period is interpreted as a literal. (Otherwise, the period matches any single character.)

Identifying a random repeating pattern in a structured text string

I have a string that has the following structure:
ABC_ABC_PQR_XYZ
Where PQR has the structure:
ABC+JKL
and
ABC itself is a string that can contain alphanumeric characters and a few other characters like "_", "-", "+", "." and follows no set structure:
eg.qWe_rtY-asdf or pkl123
so, in effect, the string can look like this:
qWe_rtY-asdf_qWe_rtY-asdf_qWe_rtY-asdf+JKL_XYZ
My goal is to find out what string constitutes ABC.
I was initially just using
$arrString = explode("_",$string);
to return $arrString[0] before I was made aware that ABC ($arrString[0]) itself can contain underscores, thus rendering it incorrect.
My next attempt was exlpoding it on "_" anyway and then comparing each of the exploded string parts with the first string part until I get a semblance of a pattern:
function getPatternABC($string)
{
$count = 0;
$pattern ="";
$arrString = explode("_", $string);
foreach($arrString as $expString)
{
if(strcmp($expString,$arrString[0])!==0 || $count==0)
{
$pattern = $pattern ."_". $arrString[$count];
$count++;
}
else break;
}
return substr($pattern,1);
}
This works great - but I wanted to know if there was a more elegant way of doing this using regular expressions?
Here is the regex solution:
'^([a-zA-Z0-9_+-]+)_\1_\1\+'
What this does is match (starting from the beginning of the string) the longest possible sequence consisting of the characters inside the square brackets (edit that per your spec). The sequence must appear exactly twice, each time followed by an underscore, and then must appear once more followed by a plus sign (this is actually the first half of PQR with the delimiter before JKL). The rest of the input is ignored.
You will find ABC captured as capture group 1.
So:
$input = 'qWe_rtY-asdf_qWe_rtY-asdf_qWe_rtY-asdf+JKL_XYZ';
$result = preg_match('/^([a-zA-Z0-9_+-]+)_\1_\1\+/', $input, $matches);
if ($result) {
echo $matches[2];
}
See it in action.
Sure, just make a regular expression that matches your pattern. In this case, something like this:
preg_match('/^([a-zA-Z0-9_+.-]+)_\1_\1\+JKL_XYZ$/', $string, $match);
Your ABC is in $match[1].
If the presence of underscores in these strings has a low frequency, it may be worth checking to see if a simple explode() will do it before bothering with regex.
<?php
$str = 'ABC_ABC_PQR_XYZ';
if(substr_count($str, '_') == 3)
$abc = reset(explode('_', $str));
else
$abc = regexy_function($str);
?>

Split alphanumeric string between leading digits and trailing letters

I have a string like:
$Order_num = "0982asdlkj";
How can I split that into the 2 variables, with the number as one element and then another variable with the letter element?
The number element can be any length from 1 to 4 say and the letter element fills the rest to make every order_num 10 characters long in total.
I have found the php explode function...but don't know how to make it in my case because the number of numbers is between 1 and 4 and the letters are random after that, so no way to split at a particular letter.
You can use preg_split using lookahead and lookbehind:
print_r(preg_split('#(?<=\d)(?=[a-z])#i', "0982asdlkj"));
prints
Array
(
[0] => 0982
[1] => asdlkj
)
This only works if the letter part really only contains letters and no digits.
Update:
Just to clarify what is going on here:
The regular expressions looks at every position and if a digit is before that position ((?<=\d)) and a letter after it ((?=[a-z])), then it matches and the string gets split at this position. The whole thing is case-insensitive (i).
Use preg_match() with a regular expression of (\d+)([a-zA-Z]+). If you want to limit the number of digits to 1-4 and letters to 6-9, change it to (\d+{1,4})([a-zA-Z]{6,9}).
preg_match("/(\\d+)([a-zA-Z]+)/", "0982asdlkj", $matches);
print("Integer component: " . $matches[1] . "\n");
print("Letter component: " . $matches[2] . "\n");
Outputs:
Integer component: 0982
Letter component: asdlkj
http://ideone.com/SKtKs
You can also do it using preg_split by splitting your input at the point which between the digits and the letters:
list($num,$alpha) = preg_split('/(?<=\d)(?=[a-z]+)/i',$Order_num);
You can use a regex for that.
preg_match('/(\d{1,4})([a-z]+)/i', $str, $matches);
array_shift($matches);
list($num, $alpha) = $matches;
Check this out
<?php
$Order_num = "0982asdlkj";
$split=split("[0-9]",$Order_num);
$alpha=$split[(sizeof($split))-1];
$number=explode($alpha, $Order_num);
echo "Alpha -".$alpha."<br>";
echo "Number-".$number[0];
?>
with regards
wazzy
My preferred approach would be sscanf() because it is concise, doesn't need regex, offers the ability to cast the numeric segment as integer type, and doesn't generate needless fullstring matches like preg_match(). %s does rely, though, on the fact that there will be no whitespaces in the letters segment of the string.
Demo
$Order_num = "0982asdlkj";
var_export (
sscanf($Order_num, '%d%s')
);
This can also be set up to declare individual variables.
sscanf($Order_num, '%d%s', $numbers, $letters)
If wanting to use a preg_ function, preg_split() is most appropriate, but I wouldn't use expensive lookarounds. Match the digits, then forget them (with \K). This will split the string without consuming any characters. Demo
var_export (
preg_split('/\d+\K/', $Order_num)
);
To assign variables, use "symmetric array destructuring".
[$numbers, $letters] = preg_split('/\d+\K/', $Order_num);
Beyond these single function approaches, there will be MANY two function approaches like:
$numbers = rtrim($Order_num, 'a..z');
$letters = ltrim($Order_num, '0..9');
But I wouldn't use them in a professional script because they lack elegance.

Categories