How to output decimal numbers in PHP? - php

I'm trying to pull two numbers from a variable($text) and then multiply them and output the results. The two numbers can be ints and floats.
When I try:
$text = "1 photograph - b&w - 2 x 5 in."
I get: The image area is 10 Which is what I want
<?php
$text = "1 photograph - b&w - 2 x 5.5 in.";
if (preg_match("/[[:digit:]]*\ x [[:digit:]]* /", $text, $match)) :
print_r($match);
$dimensions = trim($match[0]);
$dimensions = explode(" x ",$dimensions);
$image_area = (($dimensions[0]) * ($dimensions[1]));
echo 'The image area is '.($image_area);
endif;
?>
But when I try:
$text = "1 photograph - b&w - 2 x 5.5 in."
I get a blank screen
How would I output floats?
my code and output:http://sandbox.onlinephpfunctions.com/code/4b45219fdcb7864442268459621bb506c24ce78f

You have an extra space at the end of the regex, which would break it. Remove it, and it would match 2 x 5. You should be able to extend it further by adding \. to each side of the regex:
if (preg_match("/[[:digit:]\.]*\ x [[:digit:]\.]*/", $text, $match)) {

The regex expression isn't robust enough to distinguish between whole numbers and decimal numbers. The [[:digit:]] operator only matches characters 0-9.
This site is useful for creating and testing regex:
https://regex101.com/

Your regex does not match. You want:
/\d+(?:\.\d+)? x \d+(?:\.\d+)? /
1 or more digits, (optional: dot, 1 or more digits), space, x, space, 1 or more digits, (optional: dot, 1 or more digits), space
test online

Related

PHP regex to convert dimensions like N*N and NxN into N x N

I have a series of search terms entered by users, asking the same thing in different ways. For example someone is searching for frame 8 x 10 frame. They often search in the following ways:
8x10 frame
8*10 frame
8 * 10 frame
8 x 10 frame
8x10 photo frame
Stylistically, I prefer N x N, so I would prefer to convert all variations of NxN, N*N, N * N into N x N.
Examples:
8x10 frame -> 8 x 10 frame
8*10 frame -> 8 x 10 frame
8x10 photo frame -> 8 x 10 photo frame
I've tried using str_replace, but there are so many if-else conditions my code has become unmanageable. I feel like I'm not the first to have this issue, hoping some nice regex or build-in function exists.
EDIT: I used "8 x 10" as an example, but we need to consider any custom combinations like "4 x 3", "12 x 4" and so on.
Using a regular expression, you can use...
echo preg_replace("/(\d+)\s*[Xx\*]\s*(\d+)/", "$1 x $2", $a);
the pattern is
(\d+) - Any number of digits
\s* - 0 or more spaces
[Xx\*] - either X, x or *
\s* - 0 or more spaces
(\d+) - Any number of digits
which gets replaced with "$1 x $2", so this gives the consistent output.
Match a digit, then zero or one space, then either an x or a *, then zero or one space, then a digit.
If you'd rather have "zero or more" instead of "zero or one", then replace the ?s with *s.
The \K restarts the fullstring match -- so it "forgets" the first matched digit.
The "lookahead" ensures that the digit after the dimension-delimiter is found but not included in the fullstring match.
Using the i pattern modifier means case-insensitive matching.
With this pattern you don't need to bother capturing whole number sequences and your replacement string is much simpler to read.
A * inside of a character class never needs to be escaped.
Code: (Demo)
$strings = [
'8x10 frame',
'8*10 frame',
'8 * 10 frame',
'8 x 10 frame',
'8x10 photo frame'
];
var_export(preg_replace('~\d\K ?[x*] ?(?=\d)~i', ' x ', $strings));
Output:
array (
0 => '8 x 10 frame',
1 => '8 x 10 frame',
2 => '8 x 10 frame',
3 => '8 x 10 frame',
4 => '8 x 10 photo frame',
)
Using str_replace seems to work pretty well. If you have a large number of conversions that need to be done it would be pretty easy to write a couple of more lines of code to build the look for and change to arrays.
$data = ['8x10 frame','8*10 frame','8 * 10 frame','8 x 10 frame','8x10 photo frame'];
$look4 = ['*','8*' ,'8x' ,'x10',' '];
$change2 = ['x','8 *','8 x','x 10',' '];
foreach ($data as $entry) {
echo '*' . $entry . '* -> *' . str_replace($look4,$change2,$entry) . '*' . PHP_EOL;
}

How to split phone numbers in string with spaces use php

I have different strings, contains phone numbers like this:
New order to car wash #663. Customer number is 7962555443. Thank you.
or
New order to car wash #663. Customer number is 50414. Thank you, bye.
or
New order to car wash #663. A phone number to connect with the customer is 905488739038.
I need this:
New order to car wash #663. Customer number is 7 9 6 2 5 5 5 4 4 3. Thank you.
or
New order to car wash #663. Customer number is 5 0 4 1 4. Thank you, bye.
or
New order to car wash #663. A phone number to connect with the customer is 9 0 5 4 8 8 7 3 9 0 3 8.
I need to separate numbers contains more than 3 symbols.
preg_replace alone without any callback function would be sufficient.
preg_replace('~#\d+(*SKIP)(*F)|(?<=\d)(?=\d)~', ' ', $str);
DEMO
#\d+(*SKIP)(*F) Matches and discards all the numbers which starts with #.
| OR
(?<=\d)(?=\d) Now from the remaining string, this would match the boundary which exists between two digits.
Now by replacing the matched boundary with space will give you the desired output.
You could use a callback for this:
$str = preg_replace_callback('~\b\d{4,}~',
function($m) {
return implode(' ', str_split($m[0]));
}, $str);
eval.in
Also can do this by using the \G anchor. Replace with matched digit + space: "$0 "
I need to separate numbers contains more than 3 symbols.
$str = preg_replace('~\b\d(?=\d{3})|\G\d\B~', "$0 ", $str);
\b\d matches a word-boundary \b followed by a digit (\d is a short for [0-9])
(?=\d{3}) Using a lookahead to check next 3 after first \d are digits too
|\G\d\B OR match a digit at \G end of previous match followed by \B non word-boundary
See test at regex101 or eval.in
As an alternative could also replace first digit after a \h horizontal space: \h\d|\G\d\B
Try this.
$phonenumber="7962555443";
$formatted = implode(' ',str_split($phonenumber));
You can use implode you just need to use str_split first which converts the string to an array:
$number="905488739038";
$formatted = implode(' ',str_split($number));
echo $formatted;
Output:
9 0 5 4 8 8 7 3 9 0 3 8
Ref: http://www.php.net/manual/en/function.str-split.php
You may try this regex as well:
((?:(?:\d)\s?){4,})
It will capture all the number having length four or more. Also you need to do an additional step to remove spaces from the matches from the results like this:
7 9 6 2 5 5 5 4 4 3
Demo

Regular expression currency format with dots and comma

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;

Split text into words & numbers with unicode support (preg_split)

I'm trying to split (with preg_split) a text with a lot of foreign chars and digits into words and numbers with length >= 2 and without ponctuation.
Now I have this code but it only split into words without taking account digits and length >= 2 for all.
How can I do please?
$text = 'abc 文 字化け, efg Yukarda mavi gök, asağıda yağız yer yaratıldıkta; (1998 m. siejės 7 d.). Ton pate dėina bandomkojė бойынша бірінші орында тұр (79.65 %), айына 41';
$splitted = preg_split('#\P{L}+#u', $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
Expected result should be : array('abc', '字化け', 'efg', 'Yukarda', 'mavi', 'gök', 'asağıda', 'yağız', 'yer', 'yaratıldıkta', '1998', 'siejės', 'Ton', 'pate', 'dėina', 'bandomkojė', 'бойынша', 'бірінші', 'орында', 'тұр', '79.65', 'айына', '41');
NB : already tried with these docs link1 & link2 but i can't get it works :-/
Use preg_match_all instead, then you can check the length condition (that is hard to do with preg_split, but not impossible):
$text = 'abc 文 字化け, efg Yukarda mavi gök, asağıda yağız yer yaratıldıkta; (1998 m. siejės 7 d.). Ton pate dėina bandomkojė бойынша бірінші орында тұр (79.65 %), айына 41';
preg_match_all('~\p{L}{2,}+|\d{2,}+(?>\.\d++)?|\d\.\d++~u',$text,$matches);
print_r($matches);
explanation:
p{L}{2,}+ # letter 2 or more times
| # OR
\d{2,}+ # digit 2 or more times
(?>\.\d++)? # can be a decimal number
| # OR
\d\.\d++ # single digit MUST be followed by at least a decimal
# (length constraint)
With a little hack to match digits separated by dot before matching only digits as part of the word:
preg_match_all("#(?:\d+\.\d+|\w{2,})#u", $text, $matches);
$splitted = $matches[0];
http://codepad.viper-7.com/X7Ln1V
Splitting CJK into "words" is kind of meaningless. Each character is a word. If you use whitespace the you split into phrases.
So it depends on what you're actually trying to accomplish. If you're indexing text, then you need to consider bigrams and/or CJK idioms.

What is the regex of extracting single letter or two letters?

There are two string
$str = "Calcium Plus Non Fat Milk Powder 1.8kg";
$str2 = "Super Dry Diapers L 54pcs";
I use
preg_match('/(?P<name>.*) (?P<total_weight>\b[0-9]*\.?[0-9]+)(?P<total_weight_unit>.*)/', $str, $m);
to extract $str and $str2 is similar way.
However I want to extract them such that I know it is weight(i.e. kg, g, etc) or it is portion(i.e. pcs, cans).
How can I do this??
If you want to capture number and unit for pieces and weight at the same time, try this:
$number_pattern="(\d+(?:\.\d+))"; #a sequence of digit with optional fractional part
$weight_unit_pattern="(k?g|oz)"; # kg, g or oz (add any other measure with '|measure'
$number_of_pieces_pattern="(\d+)\s*(pcs)"; # capture the number of pieces
$pattern="/(?:$number_pattern\s*$weight_unit_pattern)|(?:$number_pattern\s*$number_of_pieces_pattern)/";
preg_match_all($pattern,$str1,$result);
#now you should have a number and a unit
maybe
$str = "Calcium Plus Non Fat Milk Powder 1.8kg";
$str2 = "Super Dry Diapers L 54pcs";
$pat = '/([0-9.]+).+/';
preg_match_all($pat, $str2, $result);
print_r($result);
I would suggest ([0-9]+)([^ |^<]+) or ([0-9]+)(.{2,3})
I think you are looking for this code:
preg_match('/(?P<name>.*) (?P<total_weight>\b[0-9]*(\.?[0-9]+)?)(?P<total_weight_unit>.*)/', $str, $m);
I've added parentheses which bounds fractional part. Question mark (?) means zero or one match.

Categories