Formatting decimal output when multiplying all numerical values in a string? - formatting

I have this case where I have to multiply the numbers of a string but some of the values are in EUR and some are percentage. I made it this far as code goes:
$string = "description: test1: 10 €, test2: 7.50 €, test3: 25%, test4: 30%";
$levelamt = 0.75;
$description = preg_replace_callback('/([0-9]+)\s*(\s€|%)/i', function($matches) use ($levelamt){
return ($matches[1] * $levelamt).$matches[2];
}, $string);
echo $description;
But it outputs this:
description: test1: 7.5 €, test2: 7.37.5 €, test3: 18.75%, test4:
22.5%
How should I modify the regular expression to multiply decimals and round the results of numbers? I want output to be like so:
description: test1: 7.50 €, test2: 5.63 €, test3: 18.75%,
test4: 22.5%
So when it is € value to format it XX.YY € and when it is percentage value to format it XX.YY% when percentage is a hundreds and XX.Y% when percentage decimal is a tenth. I tried rounding. Maybe I do not put it in the right place. I also tried replacing [0-9] part of the regex to find only decimals but this brings in other problems. A bit stuck here. Any help appreciated! Thanks!

You may use
$string = "description: test1: 10 €, test2: 7.50 €, test3: 25%, test4: 30%";
$levelamt = 0.75;
$description = preg_replace_callback('/(\d+(?:\.\d+)?)(\s*[€%])/i', function($matches) use ($levelamt){
return number_format(round(($matches[1] * $levelamt), 2), 2).$matches[2];
}, $string);
echo $description;
// => description: test1: 7.50 €, test2: 5.63 €, test3: 18.75%, test4: 22.50%
See the PHP demo
The regex will match
(\d+(?:\.\d+)?) - Group 1: one or more digits followed with an optional sequence of a . followed with 1+ digits
(\s*[€%]) - Group 2: 0+ whitespaces followed with € or %.
The round function will round the result of the multiplication and number_format will format the number as you need, with 2 digits after the decimal separator.

Related

format six digit numeric number comma separated in mule 4

I am having the below payload
{
"data": {
"Final_band": {
"min": "229573",
"max": "292184"
}
},
"message": "Engine pricing details fetched successfully"
}
Now I am trying to format the values "min": "229573" and "max": "292184" into something like 2,29,573 and 2,92,184.
The problem is I am trying every solution, but I am not getting the desired result
%dw 2.0
import * from dw::util::Values
var minV = round(payload.data.Final_band.min as Number ) as String {format: "#,##,###"}
var maxV = round(payload.data.Final_band.max as Number) as String {format: "#,##,###"}
output application/json
---
{
"Final_band": {
"min": minV,
"max": maxV
}
}
Firstly, I am rounding off the numeric values, and then I coercing the same into string and then applying format: "#,##,###"
but it outputs the "min":"229,573" and "max": "292,184"
it is working fine for format: "#,#####"
i,e "min":"2,29573" and "max": "2,92184"
but when I add more comma(,) for thousand place, it won't work as expected
The formatting of number in Dataweave is based on java.text.DecimalFormat (reference). Which does not support variable width groups. I only see you have two options.
You will either have to use another 3rd party java library that can handle this and use Java module to invoke the required methods.
You can implement your own logic which is fairly easy for this in Dataweave. (Infact if you see in the other java question, most answers have suggested their own implementation)
%dw 2.0
output application/json
/**
* Strip the last digit of number. If decimal strip the number after decimal along with the last digit of whole number
* Format the remaining numbers with ##,##.
* Append the stripped part to this formatted number.
*/
fun indianFormatNum(num: Number) =
if(num >= 0 and num < 10) num // otherwise this will pad single digit numbers with a 0
else do {
//lets say input is 123456.78
var appendLater = (num mod 10) as String // value will be 6.78
var remainingNumner = floor(num / 10) // value will be 12345
---
remainingNumner as String {format: "##,##"} ++ appendLater
// 1,23,45 ++ 6.78
}
---
{
a: indianFormatNum(12345), // outputs 12,345
b: indianFormatNum(123457.89), // outputs 1,23,457.89
c: indianFormatNum(8)
}

Kotlin/Java formatting Double values

My current formatting is this
DecimalFormat("#,##0.00").format(value)
I need to handle values like this
0.00 //ok
0.45 //ok
0.002 //Need to show 0.002 or 0.0020
0.0003 //Need to show 0.0003 or 0.00030
0.00004 //Need to show 0.00004 or 0.000040
0.00234567 //Need to show 0.0023
But sure the above code will not work on fractional part where a non zero value started at thousandth place else I will just ended up displaying 0.00 as if it is totally a zero value. I still want the above formatting with comma when dealing with whole number but also allowing me to format when non zero starts beyond hundredths place.
Further sample
0.0492 // 0.04 or 0.05 much better
700.356 // 700.35 or 700.36 much better
54232.542234 // 54,232.54
Try multiplying the number by 10 until you know you got to two non zero digits. This way you will get the number of decimal points you have to round up.
After that you use the NumberFormat to format the number like this:
val format = NumberFormat.getInstance()
format.maximumFractionDigits = nrOfDecimalPoints
val formattedNumber = format.format(yourNumber)
This way you will keep the thousands separator "," and the decimal will be cut off after two non zero digits.
EDIT
This is how the custom function looks like:
private fun customFormat(number: Double): String{
var temp = number - number.toInt()
temp *= 100
var nrDec = 2
if (number <= 0.0){
return "0.00"
}
if (temp >= 1.0){
val format = NumberFormat.getInstance(Locale.US)
format.maximumFractionDigits = nrDec
return format.format(number)
}
while (temp < 1.0 && nrDec < 15){
temp *= 10
nrDec ++
}
if((temp * 10 % 10) != 0.0){
nrDec++
}
val format = NumberFormat.getInstance(Locale.US)
format.maximumFractionDigits = nrDec
return format.format(number)
}
You can do it like this in order to cut of tailing 0:
public static void main(String []args){
double number1 = 0.2;
double number2 = 1.55;
double number3 = 0.00005;
double number4 = 0.50000;
DecimalFormat df = new DecimalFormat("###,##0.00#########");
System.out.println(df.format(number1)); // 0.20
System.out.println(df.format(number2)); // 1.55
System.out.println(df.format(number3)); // 0.00005
System.out.println(df.format(number4)); // 0.50
}
You just need to know how far your decimal digits should be checked.

Incorrect number of parameters passed to subroutine

In perl6 I define a subroutine with two parameters, one a scalar and the other an array. When I call the subroutine I receive a run-time error saying that only one parameter was passed when two were expected.
I have tried redefining the subroutine with only one parameter, once for each parameter type, and these cases succeed.
my #bb="red", "orange", "yellow", "green", "bleu", "indigo", "violet";
sub1(#bb,123);
sub sub1(#val2, $v) {
print "\#val2 = #val2\n";
print "\$v = $v\n";
}
I expect the output to be:
red orange yellow green blue indigo violet
123
The actual result is:
Too few positionals passed; expected 2 arguments but got 1

Less - How to replace integer with a string?

I have a LESS variable:
#columns: 12;
I create a dynamic class name out of it:
.one-#{columns} {} // returns .one-12 {}
How do I replace the 12 with a string "twelfth"
Pseudo Code
.one-#{replace(columns, "twelfth")} {}
The result will be .one-twelfth {}
Advice will be appreciated!
Assuming (as revealed in comments) you can't change the value of #columns variable itself and its possible values are not infinite, a trivial integer to string (or anything else) conversion table (a simple list) will do the trick:
#columns: 12;
#columns-string: extract(#i2s, #columns);
// usage:
.class-#{columns-string} {
/* ... */
}
// the table:
#i2s:
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
thirteen
fourteen
fifteen
sixteen
seventeen
eighteen
nineteen
twenty
;
The solution to this is to use array:
Instead of #columns: 12
I do #columns: 12, twelfth.
Then I extract values:
#columns-number: extract(#columns, 1);
#columns-class: extract(#columns, 2);
The I can target value and a class name with mixin:
.#{columns-class} {
.column(#columns-number);
}

Regular Expression for validate price in decimal

I really unable to find any workaround for regular expression to input price in decimal.
This what I want:-
12345
12345.1
12345.12
12345.123
.123
0.123
I also want to restrict digits.
I really created one but not validating as assumed
^([0-9]{1,5}|([0-9]{1,5}\.([0-9]{1,3})))$
Also want to know how is above expression different from the one
^([0-9]{1,5}|([0-9].([0-9]{1,3})))$ thats working fine.
Anyone with good explanation.
"I am using NSRegularExpression - Objective C" if this helps to answer more precisely
- (IBAction)btnTapped {
NSRegularExpression * regex = [NSRegularExpression regularExpressionWithPattern:
#"^\\d{1,5}([.]\\d{1,3})?|[.]\\d{1,3}$" options:NSRegularExpressionCaseInsensitive error:&error];
if ([regex numberOfMatchesInString:txtInput.text options:0 range:NSMakeRange(0, [txtInput.text length])])
NSLog(#"Matched : %#",txtInput.text);
else
NSLog(#"Not Matched : %#",txtInput.text);
}
"I am doing it in a buttonTap method".
This simple one should suit your needs:
\d*[.]?\d+
"Digits (\d+) that can be preceded by a dot ([.]?), which can itself be preceded by digits (\d*)."
Since you're talking about prices, neither scientific notation nor negative numbers are necessary.
Just as a point of interest, here's the one I usually used, scientific notation and negative numbers included:
[-+]?\d*[.]?\d+(?:[eE][-+]?\d+)?
For the new requirements (cf. comments), you can't specify how many digits you want on the first regex I gave, since it's not the way it has been built.
This one should suit your needs better:
\d{1,5}([.]\d{1,3})?|[.]\d{1,3}
"Max 5 digits (\d{1,5}) possibly followed ((...)?) by a dot itself followed by max 3 digits ([.]\d{1,3}), or (|) simply a dot followed by max 3 digits ([.]\d{1,3})".
Let's do this per-partes:
Sign in the beginning: [+-]?
Fraction number: \.\d+
Possible combinations (after sign):
Number: \d+
Fraction without zero \.\d+
And number with fraction: \d+\.\d+
So to join it all together <sign>(number|fraction without zero|number with fraction):
^[+-]?(\d+|\.\d+|\d+\.\d+)$
If you're not restricting the lengths to 5 digits before the decimal and 3 digits after then you could use this:
^[+-]?(?:[0-9]*\.[0-9]|[0-9]+)$
If you are restricting it to 5 before and 3 after max then you'd need something like this:
^[+-]?(?:[0-9]{0,5}\.[0-9]{1,3}|[0-9]{1,5})$
As far as the difference between your regexes goes, the first one limits the length of the number of digits before the decimal marker to 1-5 with and without decimals present. The second one only allows a single digit in front of the decimal pointer and 1-5 digits if there is no decimal.
How about this: ^([+-])?(\d+)?([.,])?(\d+)?$
string input = "bla";
if (!string.IsNullOrWhiteSpace(input))
{
string pattern = #"^(\s+)?([-])?(\s+)?(\d+)?([,.])?(\d+)(\s+)?$";
input = input.Replace("\'", ""); // Remove thousand's separator
System.Text.RegularExpressions.Regex.IsMatch(input, pattern);
// if server culture = de then reverse the below replace
input = input.Replace(',', '.');
}
Edit:
Oh oh - just realized that's where we run into a little bit of a problem if an en-us user uses ',' as thousand's separator....
So here a better one:
string input = "+123,456";
if (!string.IsNullOrWhiteSpace(input))
{
string pattern = #"^(\s+)?([+-])?(\s+)?(\d+)?([.,])?(\d+)(\s+)?$";
input = input.Replace(',', '.'); // Ensure no en-us thousand's separator
input = input.Replace("\'", ""); // Remove thousand's separator
input = System.Text.RegularExpressions.Regex.Replace(input, #"\s", ""); // Remove whitespaces
bool foo = System.Text.RegularExpressions.Regex.IsMatch(input, pattern);
if (foo)
{
bool de = false;
if (de) // if server-culture = de
input = input.Replace('.', ',');
double d = 0;
bool bar = double.TryParse(input, out d);
System.Diagnostics.Debug.Assert(foo == bar);
Console.WriteLine(foo);
Console.WriteLine(input);
}
else
throw new ArgumentException("input");
}
else
throw new NullReferenceException("input");
Edit2:
Instead of going through the hassle of getting the server culture, just use the tryparse overload with the culture and don't resubstitute the decimal separator.
double.TryParse(input
, System.Globalization.NumberStyles.Any
, new System.Globalization.CultureInfo("en-US")
, out d
);