Parsing String to Double including scientific notation E - java

I use Choco constraint solver to solve a problem.
I use RealVariables x, y and z.
The solution looks like this
x[3.9999999999999996, 4.000000000000001]
y[-3.1434555694057773E-162, 3.1434555694057773E-162]
z[-3.1434555694057773E-162, 3.1434555694057773E-162]
And I try to parse the solutions to double variables.
Here is my code:
String X = s.getVar(x).toString();
String Y = s.getVar(y).toString();
String Z = s.getVar(z).toString();
Matcher match = Pattern.compile("-?\\d+(\\.\\d+)?").matcher(X);
while(match.find())
{
double d = Double.parseDouble(match.group());
System.out.println("value= " + d);
}
match = Pattern.compile("-?\\d+(\\.\\d+)?").matcher(Y);
while(match.find())
{
DecimalFormat format = new DecimalFormat("0.00");
Double d = Double.parseDouble(match.group());
System.out.println("value= " + format.format(d));
}
match = Pattern.compile("-?\\d+(\\.\\d+)?").matcher(Z);
while(match.find())
{
double d = Double.parseDouble(match.group());
System.out.println("parsed: " + d);
}
The output is:
parsed: 3.9999999999999996
parsed: 4.000000000000001
parsed: -3,14
parsed: -162,00
parsed: 3,14
parsed: -162,00
parsed: -3.143455569405777
parsed: -162.0
parsed: 3.143455569405777
parsed: -162.0
Which means, -162 is parsed like another double. How do I prevent this? How can I parse a String to Double using scientific notation?
Does this happen because E-162 is too long for Double?

You need to change your pattern to take account of the exponant:
Matcher match = Pattern.compile("-?\\d+(\\.\\d+)?(E-?\\d+)?").matcher(X);
Note: The capturing groups are not needed here, you can replace them by non-capturing groups (?:...).
Since you will use the same regex several times, it is better to define the pattern once and for all, instead of repeating Pattern.compile("-?\\d+(\\.\\d+)?(E-?\\d+)?"). You can use this:
static Pattern pattern = Pattern.compile("-?\\d+(?:\\.\\d+)?(?:E-?\\d+)?");
....
Matcher match = pattern.matcher(X);
....
match = pattern.matcher(Y);
....
match = pattern.matcher(Z);

Double#parseDouble parses doubles from Strings and it parses the exponet aswell.
System.out.println(Double.parseDouble("1.2345e5"));
--> 123450.0
Example: https://ideone.com/ACTVQT

To catch all numbers in Java from regex use this pattern
"-?\\d+(\\.\\d+)?(E-?\\d+)?(E\\+?\\d+)?(E?\\d+)?(e-?\\d+)?(e\\+?\\d+)?(e?\\d+)?"
I have tried this regex on following strings and all of them returned true
"2546546516",
"-2546546516",
"2546546516.1241546",
"-2546546516.415441",
"2.5465E+09",
"-2.5465E+09",
"2.5465E-09",
"-2.5465E-09",
"2.5465e+09",
"-2.5465e+09",
"2.5465e-09",
"-2.5465e-09",
"445.4e2",
"-445.4e2"
Note: This answer was inspired by Casimir's answer
PS. Edits are welcome

Related

Remove elements from Date Format String using a Regular Expression

I want to remove elements a supplied Date Format String - for example convert the format "dd/MM/yyyy" to "MM/yyyy" by removing any non-M/y element.
What I'm trying to do is create a localised month/year format based on the existing day/month/year format provided for the Locale.
I've done this using regular expressions, but the solution seems longer than I'd expect.
An example is below:
public static void main(final String[] args) {
System.out.println(filterDateFormat("dd/MM/yyyy HH:mm:ss", 'M', 'y'));
System.out.println(filterDateFormat("MM/yyyy/dd", 'M', 'y'));
System.out.println(filterDateFormat("yyyy-MMM-dd", 'M', 'y'));
}
/**
* Removes {#code charsToRetain} from {#code format}, including any redundant
* separators.
*/
private static String filterDateFormat(final String format, final char...charsToRetain) {
// Match e.g. "ddd-"
final Pattern pattern = Pattern.compile("[" + new String(charsToRetain) + "]+\\p{Punct}?");
final Matcher matcher = pattern.matcher(format);
final StringBuilder builder = new StringBuilder();
while (matcher.find()) {
// Append each match
builder.append(matcher.group());
}
// If the last match is "mmm-", remove the trailing punctuation symbol
return builder.toString().replaceFirst("\\p{Punct}$", "");
}
Let's try a solution for the following date format strings:
String[] formatStrings = { "dd/MM/yyyy HH:mm:ss",
"MM/yyyy/dd",
"yyyy-MMM-dd",
"MM/yy - yy/dd",
"yyabbadabbadooMM" };
The following will analyze strings for a match, then print the first group of the match.
Pattern p = Pattern.compile(REGEX);
for(String formatStr : formatStrings) {
Matcher m = p.matcher(formatStr);
if(m.matches()) {
System.out.println(m.group(1));
}
else {
System.out.println("Didn't match!");
}
}
Now, there are two separate regular expressions I've tried. First:
final String REGEX = "(?:[^My]*)([My]+[^\\w]*[My]+)(?:[^My]*)";
With program output:
MM/yyyy
MM/yyyy
yyyy-MMM
Didn't match!
Didn't match!
Second:
final String REGEX = "(?:[^My]*)((?:[My]+[^\\w]*)+[My]+)(?:[^My]*)";
With program output:
MM/yyyy
MM/yyyy
yyyy-MMM
MM/yy - yy
Didn't match!
Now, let's see what the first regex actually matches to:
(?:[^My]*)([My]+[^\\w]*[My]+)(?:[^My]*) First regex =
(?:[^My]*) Any amount of non-Ms and non-ys (non-capturing)
([My]+ followed by one or more Ms and ys
[^\\w]* optionally separated by non-word characters
(implying they are also not Ms or ys)
[My]+) followed by one or more Ms and ys
(?:[^My]*) finished by any number of non-Ms and non-ys
(non-capturing)
What this means is that at least 2 M/ys are required to match the regex, although you should be careful that something like MM-dd or yy-DD will match as well, because they have two M-or-y regions 1 character long. You can avoid getting into trouble here by just keeping a sanity check on your date format string, such as:
if(formatStr.contains('y') && formatStr.contains('M') && m.matches())
{
String yMString = m.group(1);
... // other logic
}
As for the second regex, here's what it means:
(?:[^My]*)((?:[My]+[^\\w]*)+[My]+)(?:[^My]*) Second regex =
(?:[^My]*) Any amount of non-Ms and non-ys
(non-capturing)
( ) followed by
(?:[My]+ )+[My]+ at least two text segments consisting of
one or more Ms or ys, where each segment is
[^\\w]* optionally separated by non-word characters
(?:[^My]*) finished by any number of non-Ms and non-ys
(non-capturing)
This regex will match a slightly broader series of strings, but it still requires that any separations between Ms and ys be non-words ([^a-zA-Z_0-9]). Additionally, keep in mind that this regex will still match "yy", "MM", or similar strings like "yyy", "yyyy"..., so it would be useful to have a sanity check as described for the previous regular expression.
Additionally, here's a quick example of how one might use the above to manipulate a single date format string:
LocalDateTime date = LocalDateTime.now();
String dateFormatString = "dd/MM/yyyy H:m:s";
System.out.println("Old Format: \"" + dateFormatString + "\" = " +
date.format(DateTimeFormatter.ofPattern(dateFormatString)));
Pattern p = Pattern.compile("(?:[^My]*)([My]+[^\\w]*[My]+)(?:[^My]*)");
Matcher m = p.matcher(dateFormatString);
if(dateFormatString.contains("y") && dateFormatString.contains("M") && m.matches())
{
dateFormatString = m.group(1);
System.out.println("New Format: \"" + dateFormatString + "\" = " +
date.format(DateTimeFormatter.ofPattern(dateFormatString)));
}
else
{
throw new IllegalArgumentException("Couldn't shorten date format string!");
}
Output:
Old Format: "dd/MM/yyyy H:m:s" = 14/08/2019 16:55:45
New Format: "MM/yyyy" = 08/2019
I'll try to answer with the understanding of my question : how do I remove from a list/table/array of String, elements that does not exactly follow the patern 'dd/MM'.
so I'm looking for a function that looks like
public List<String> removeUnWantedDateFormat(List<String> input)
We can expect, from my knowledge on Dateformat, only 4 possibilities that you would want, hoping i dont miss any, which are "MM/yyyy", "MMM/yyyy", "MM/yy", "MM/yyyy". So that we know what we are looking for we can do an easy function.
public List<String> removeUnWantedDateFormat(List<String> input) {
String s1 = "MM/yyyy";
string s2 = "MMM/yyyy";
String s3 = "MM/yy";
string s4 = "MMM/yy";
for (String format:input) {
if (!s1.equals(format) && s2.equals(format) && s3.equals(format) && s4.equals(format))
input.remove(format);
}
return input;
}
Better not to use regex if you can, it costs a lot of resources. And great improvement would be to use an enum of the date format you accept, like this you have better control over it, and even replace them.
Hope this will help, cheers
edit: after i saw the comment, i think it would be better to use contains instead of equals, should work like a charm and instead of remove,
input = string expected.
so it would looks more like:
public List<String> removeUnWantedDateFormat(List<String> input) {
List<String> comparaisons = new ArrayList<>();
comparaison.add("MMM/yyyy");
comparaison.add("MMM/yy");
comparaison.add("MM/yyyy");
comparaison.add("MM/yy");
for (String format:input) {
for(String comparaison: comparaisons)
if (format.contains(comparaison)) {
format = comparaison;
break;
}
}
return input;
}

Is locale aware parsing for Numberformat possible in Android?

I have an Android application which does some basic mathematics.
Example
try {
NumberFormat nf = NumberFormat.getNumberInstance();
DecimalFormat df = (DecimalFormat) nf;
a = Float.parseFloat(vw3.getText().toString());
f = Float.parseFloat(vw5.getText().toString());
c = a / 100;
d = c * 1.036f;
e = f / 100;
g = e * 1.24f;
h = d + g;
String str1 = String.valueOf(df.format(h));
vw7.setText(str1);
} catch (NumberFormatException f) {
a = (0);
}
}
When the user is in the USA the calculations work fine and format fine. Well as you would expect. The 1,000.00 format where the grouping is by comma and separator is by decimal point. When a user is in France, the grouping is different and the separator is also different. Using the 1,000.00 example, in France the number would be formatted like this 1 000,00. A space is the grouping separator and the comma is the decimal separator. This causes a problem when you try and run a calculation and you will get a NumberFromatException (NFE). And I anticipated a NFE issue and catch it and replace the possible cause with the correct number. However, replacing any comma with a space and any period with a comma will also produce a NFE.
Example
try {
NumberFormat nf = NumberFormat.getNumberInstance();
DecimalFormat df = (DecimalFormat) nf;
a = Float.parseFloat(vw3.getText().toString().replace(",",""));
f = Float.parseFloat(vw5.getText().toString().replace(",",""));
c = a / 100;
d = c * 1.036f;
e = f / 100;
g = e * 1.24f;
h = d + g;
String str1 = String.valueOf(df.format(h));
vw7.setText(str1);
} catch (NumberFormatException f) {
a = (0);
}
}
EDIT - As suggested by Peter O. I have tried parsing the number with a locale aware means.
Example
NumberFormat.getNumberInstance().parse(string);
Or
NumberFormat df = NumberFormat.getNumberInstance();
String value = "10,40 €";
Number valueParsed = df.parse(value);
vw7.setText(valueParsed);
Will produce a "Bad Class" illegalargument.
I am looking for a solution to where I can do the calculations in an acceptable manner within the apps programming regardless of the locale and then later format the results to the locale. The question could be or is, do you force a locale for your calculations and then format the results for the locale?
If this is the code you are using and your strings will have the currency symbol. In this case € the EURO symbol.
Your example:
NumberFormat df = NumberFormat.getNumberInstance();
String value = "10,40 €";
Number valueParsed = df.parse(value);
vw7.setText(valueParsed);
so that value always has a currency symbol you need to use
NumberFormat df= NumberFormat.getCurrencyInstance();
instead of the .getNumberInstance(). This worked on my system which is currently set so that the € symbols is the default currency symbol. You will have to try it on a system that has the $ currency symbol in order to verify that it works there, also.

REGEX: Get double (positive or negative) from string [duplicate]

let's say i have string like that:
eXamPLestring>1.67>>ReSTOfString
my task is to extract only 1.67 from string above.
I assume regex will be usefull, but i can't figure out how to write propper expression.
If you want to extract all Int's and Float's from a String, you can follow my solution:
private ArrayList<String> parseIntsAndFloats(String raw) {
ArrayList<String> listBuffer = new ArrayList<String>();
Pattern p = Pattern.compile("[0-9]*\\.?[0-9]+");
Matcher m = p.matcher(raw);
while (m.find()) {
listBuffer.add(m.group());
}
return listBuffer;
}
If you want to parse also negative values you can add [-]? to the pattern like this:
Pattern p = Pattern.compile("[-]?[0-9]*\\.?[0-9]+");
And if you also want to set , as a separator you can add ,? to the pattern like this:
Pattern p = Pattern.compile("[-]?[0-9]*\\.?,?[0-9]+");
.
To test the patterns you can use this online tool: http://gskinner.com/RegExr/
Note: For this tool remember to unescape if you are trying my examples (you just need to take off one of the \)
You could try matching the digits using a regular expression
\\d+\\.\\d+
This could look something like
Pattern p = Pattern.compile("\\d+\\.\\d+");
Matcher m = p.matcher("eXamPLestring>1.67>>ReSTOfString");
while (m.find()) {
Float.parseFloat(m.group());
}
Here's how to do it in one line,
String f = input.replaceAll(".*?(-?[\\d.]+)?.*", "$1");
Which returns a blank String if there is no float found.
If you actually want a float, you can do it in one line:
float f = Float.parseFloat(input.replaceAll(".*?(-?[\\d.]+).*", "$1"));
but since a blank cannot be parsed as a float, you would have to do it in two steps - testing if the string is blank before parsing - if it's possible for there to be no float.
String s = "eXamPLestring>1.67>>ReSTOfString>>0.99>>ahgf>>.9>>>123>>>2323.12";
Pattern p = Pattern.compile("\\d*\\.\\d+");
Matcher m = p.matcher(s);
while(m.find()){
System.out.println(">> "+ m.group());
}
Gives only floats
>> 1.67
>> 0.99
>> .9
>> 2323.12
You can use the regex \d*\.?,?\d* This will work for floats like 1.0 and 1,0
Have a look at this link, they also explain a few things that you need to keep in mind when building such a regex.
[-+]?[0-9]*\.?[0-9]+
example code:
String[] strings = new String[3];
strings[0] = "eXamPLestring>1.67>>ReSTOfString";
strings[1] = "eXamPLestring>0.57>>ReSTOfString";
strings[2] = "eXamPLestring>2547.758>>ReSTOfString";
Pattern pattern = Pattern.compile("[-+]?[0-9]*\\.?[0-9]+");
for (String string : strings)
{
Matcher matcher = pattern.matcher(string);
while(matcher.find()){
System.out.println("# float value: " + matcher.group());
}
}
output:
# float value: 1.67
# float value: 0.57
# float value: 2547.758
/**
* Extracts the first number out of a text.
* Works for 1.000,1 and also for 1,000.1 returning 1000.1 (1000 plus 1 decimal).
* When only a , or a . is used it is assumed as the float separator.
*
* #param sample The sample text.
*
* #return A float representation of the number.
*/
static public Float extractFloat(String sample) {
Pattern pattern = Pattern.compile("[\\d.,]+");
Matcher matcher = pattern.matcher(sample);
if (!matcher.find()) {
return null;
}
String floatStr = matcher.group();
if (floatStr.matches("\\d+,+\\d+")) {
floatStr = floatStr.replaceAll(",+", ".");
} else if (floatStr.matches("\\d+\\.+\\d+")) {
floatStr = floatStr.replaceAll("\\.\\.+", ".");
} else if (floatStr.matches("(\\d+\\.+)+\\d+(,+\\d+)?")) {
floatStr = floatStr.replaceAll("\\.+", "").replaceAll(",+", ".");
} else if (floatStr.matches("(\\d+,+)+\\d+(.+\\d+)?")) {
floatStr = floatStr.replaceAll(",", "").replaceAll("\\.\\.+", ".");
}
try {
return new Float(floatStr);
} catch (NumberFormatException ex) {
throw new AssertionError("Unexpected non float text: " + floatStr);
}
}

How can i separate this "£232.69" value without a currency symbol? I need this value to be 232.69

String Total = driver.findElement(By.xpath("wwwww")).getText();
I will get the Value £232.69 from the above code. Now I want to split the separate the Value without that Currency Symbol. Like 232.69.
So that I can compare this value with another one.
This will give you any first number (integer or not, matching expression someNumbers + optional(dot + someNumbers)) occuring in string s as a string:
String s = "&21.37";
Pattern p = Pattern.compile("[^0-9]*([0-9]+(\\.[0-9]*)?)");
Matcher m = p.matcher(s);
m.matches();
String s = m.group(1)
You can then extract it as follows:
Double d = Double.valueOf(s)
Here is updated code: , #kripindas
String s = "&1,221.37";
Pattern p = Pattern.compile("[^0-9]*([0-9]*,?([0-9]+(\\.[0-9]*))?)");
Matcher m = p.matcher(s);
m.matches();
String s_num = m.group(1).replace(",", "");
System.out.println(s_num);
Double d_num = Double.valueOf(s_num);
System.out.println(d_num);
Note that this will match:
"&1,234.56", "$123,4.5678", "JP234,123.12"
and convert them to (correspondingly):
1234.56
1234.5678
234123.12
you can use the .substring() js function for doing this. you can get more details from http://www.w3schools.com/jsref/jsref_substring.asp
use th following
String Total = driver.findElement(By.xpath("wwwww")).getText().substring(1);
I figured this out a few minutes ago.
price = driver.find_element_by_css_selector("div.teaser-pricing div.pricing").text
print(price.split()[0].replace('$', ''))
This will split it from the first index and replace what you want from the text in the second part.

Regex: How to include character of "if" condition

I'm making a date extractor using regex in java. Problem is that date is 20-05-2014 and my program is extracting 0-5-14. In short, how can I get the character on which I'm checking the second character of date?
int count = 0;
String data = "HellowRoldsThisis20-05-2014. farhan_rock#gmail.comHellowRoldsThisis.farhan#gmail.com";
String regexOfDate = "((?<=[0])[1-9]{2})|((?<=[12])[0-9])|((?<=[3])[01])\\.\\-\\_((?<=[0])[1-9])|((?<=[1])[0-2])\\.\\-\\_((?<=[2])[0-9]{4})"; \\THE PROBLEM
String[] extractedDate = new String[1000];
Pattern patternDate = Pattern.compile(regexOfDate);
Matcher matcherDate = patternDate.matcher(data);
while(matcherDate.find()){
System.out.println("Date "+count+"Start: "+matcherDate.start());
System.out.println("Date "+count+"End : "+matcherDate.end());
extractedDate[count] = data.substring(matcherDate.start(), matcherDate.end());
System.out.println("Date Extracted: "+extractedDate[count]);
}
You can try the regular expression:
// (0[1-9]|[12][0-9]|[3][01])[._-](0[1-9]|1[0-2])[._-](2[0-9]{3})
"(0[1-9]|[12][0-9]|[3][01])[._-](0[1-9]|1[0-2])[._-](2[0-9]{3})"
A single regex o match valid dates is awful.
I'd do:
String regexOfDate = "(?<!\\d)\\d{2}[-_.]\\d{2}[-_.]\\d{4}(?!\\d)";
to extract the potential date, then test if it is valid.

Categories

Resources