Formatting numbers in a mathematical expression from String values in java - java

I know how to set thousands separator for numbers but i need to display numbers with thousands separator in mathematical expression from String values.
Basically, I want these results:
"123456 + 36514" becomes "123,456 + 36,514"
"12345678 + 36542 * 69541 / 987654" becomes "12,345,678 + 36,542 * 69,541 / 987,654"
and ...

You want to insert comma after a digit that is followed by an exact number of 3-digit blocks, so:
(?<=\d) Positive lookbehind: Match a digit
(?= Positive lookahead:
(?:\d{3})+ One or more sequences of 3 digits
\b Word-boundary, i.e. end of digit sequence
)
That will match the empty spaces where you want commas, so do a replaceAll():
str = str.replaceAll("(?<=\\d)(?=(?:\\d{3})+\\b)", ",");
See regex101 for demo.

I can provide you an algorithm rather giving the code:
Loop: String of repression one character at a time
{
If the current char is 0 to 9 append to tempNumber string
else
{
//by the time you reach this line the number is in the tempNumber string
Format the number stored in tempNumber // java.text.NumberFormat
append the formatted number in targetExpression string
append the current char to the targetExpression string
}
}

Related

Length of some characters in regex

I have following regex:
\+?[0-9\.,()\-\s]+$
which allows:
optional + at the beginning
then numbers, dots, commas, round brackets, dashes and white spaces.
In addition to that I need to make sure that amount of numbers and plus symbol (if exists) has length between 9 and 15 (so I'm not counting any special characters apart from + symbol).
And this last condition is what I'm having problem with.
valid inputs:
+358 (9) 1234567
+3 5 8.9,1-2(3)4..5,6.7 (25 characters but only 12 characters that counts (numbers and plus symbol))
invalid input:
+3 5 8.9,1-2(3)4..5,6.777777777 (33 characters and only 20 characters that counts (numbers and plus symbol) is too many)
It is important to use regex if possible because it's used in javax.validation.constraints.Pattern annotation as:
#Pattern(regexp = REGEX)
private String number;
where my REGEX is what I'm looking for here.
And if regex cannot be provided then it means that I need to rewrite my entity validation implementation. So is it possible to add such condition to regex or do I need a function to validate such pattern?
You may use
^(?=(?:[^0-9+]*[0-9+]){9,15}[^0-9+]*$)\+?[0-9.,()\s-]+$
See the regex demo
Details
^ - start of string
(?=(?:[^0-9+]*[0-9+]){9,15}[^0-9+]*$) - a positive lookahead whose pattern must match for the regex to find a match:
(?:[^0-9+]*[0-9+]){9,15} - 9 to 15 repetitions of
[^0-9+]* - any 0+ chars other than digits and + symbol
[0-9+] - a digit or +
[^0-9+]* - 0+ chars other than digits and +
$ - end of string
\+? - an optional + symbol
[0-9.,()\s-]+ - 1 or more digits, ., ,, (, ), whitespace and - chars
$ - end of string.
In Java, when used with matches(), the ^ and $ anchors may be omitted:
s.matches("(?=(?:[^0-9+]*[0-9+]){9,15}[^0-9+]*$)\\+?[0-9.,()\\s-]+")
Not using regex, you could simply loop and count the numbers and +s:
int count = 0;
for (int i = 0; i < str.length(); i++) {
if (Character.isDigit(str.charAt(i)) || str.charAt(i) == '+') {
count++;
}
}
Since you're using Java, I wouldn't rely solely on a regex here:
String input = "+123,456.789";
int count = input.replaceAll("[^0-9+]", "").length();
if (input.matches("^\\+?[0-9.,()\\-\\s]+$") && count >= 9 && count <= 15) {
System.out.println("PASS");
}
else {
System.out.println("FAIL");
}
This approach allows us to just use straightaway your original regex. We handle the length requirements of numbers (and maybe plus) using Java string calls.

Mask mobile number in Java [duplicate]

I would like to mask the last 4 digits of the identity number (hkid)
A123456(7) -> A123***(*)
I can do this by below:
hkid.replaceAll("\\d{3}\\(\\d\\)", "***(*)")
However, can my regular expression really can match the last 4 digit and replace by "*"?
hkid.replaceAll(regex, "*")
Please help, thanks.
Jessie
Personally, I wouldn't do it with regular expressions:
char[] cs = hkid.toCharArray();
for (int i = cs.length - 1, d = 0; i >= 0 && d < 4; --i) {
if (Character.isDigit(cs[i])) {
cs[i] = '*';
++d;
}
}
String masked = new String(cs);
This goes from the end of the string, looking for digit characters, which it replaces with a *. Once it's found 4 (or reaches the start of the string), it stops iterating, and builds a new string.
While I agree that a non-regex solution is probably the simplest and fastest, here's a regex to catch the last 4 digits independent if there is a grouping ot not: \d(?=(?:\D*\d){0,3}\D*$)
This expression is meant to match any digit that is followed by 0 to 3 digits before hitting the end of the input.
A short breakdown of the expression:
\d matches a single digit
\D matches a single non-digit
(?=...) is a positive look-ahead that contributes to the match but isn't consumed
(?:...){0,3} is a non-capturing group with a quantity of 0 to 3 occurences given.
$ matches the end of the input
So you could read the expression as follows: "match a single digit if it is followed by a sequence of 0 to 3 times any number of non-digits which are followed by a single digit and that sequence is followed by any number of non-digits and the end of the input" (sounds complicated, no?).
Some results when using input.replaceAll( "\\d(?=(?:\\D*\\d){0,3}\\D*$)", "*" ):
input = "A1234567" -> output = "A123****"
input = "A123456(7)" -> output = "A123***(*)"
input = "A12345(67)" -> output = "A123**(**)"
input = "A1(234567)" -> output = "A1(23****)"
input = "A1234B567" -> output = "A123*B***"
As you can see in the last example the expression will match digits only. If you want to match letters as well either replace \d and \D with \w and \W (note that \w matches underscores as well) or use custom character classes, e.g. [02468] and [^02468] to match even digits only.

Regular expression for phone number starting with '00' or '+'

I've got a regex problem: I'm trying to force a phone number beginning with either "00" or "+" but my attempt doesn't work.
String PHONE_PATTERN = "^[(00)|(+)]{1}[0-9\\s.\\/-]{6,20}$";
It still allows for example "0123-45678". What am i doing wrong?
Inside character class every character is matched literally, which means [(00)|(+)] will match a 0 or + or | or ( or )
Use this regex:
String PHONE_PATTERN = "^(?:00|\\+)[0-9\\s.\\/-]{6,20}$";
if you have removed spaces, hyphens and whatever from the number, and you want to catch either +xxnnnnnnnn or 00xxnnnnnnnn where xx is the country code of course and n is the 9 digit number OR 0nnnnnnnnn where a non international number starting with a zero is followed by 9 digits then try this regex
String PHONE_PATTERN = "^(?:(?:00|\+)\d{2}|0)[1-9](?:\d{8})$"

Is there a way to stop a RegEx before a character value and start another one after that character?

I am trying to remove numbers before a character such as a-z or *, /, +, -, and then remove any numbers following that character but before a different character. Here is what I have.
s= s.replaceAll("(\\d+)", "");
s= s.replace("*", r.toString());
Where s is the string that I need to read, and r is the result of the operation.
The * is arbitrary. It could be any char. previously mentioned
The problem with this is that it removes every number in the string.
If I were to iterate once with the input of:
26 + 4 - 2
The program returns this:
30 -
It deletes all three numbers and then replaces the "+" with 30.
I would like to change it to resemble this (with one iteration):
26 + 4 - 2
The first RegEx would delete the first set of numbers
+ 4 - 2
The second would remove the numbers after the operator, but before the next operator
+ - 2
The next statement would replace the operator with the result of the expression
30 - 2
I would like the same for problems with other functions such as sine, cosine, etc.
Note: Sine is 'a'
"Sin pi" is the same as "a pi"
After one iteration it should look like
a pi + 2
a + 2
0 + 2
Here is a sample of the code.
This is the Multiply "case"
case '*':
{
int m = n + 1;
while (m < result.length){
if (result[m] != '*' && result[m] != '/' && result[m] != '+' && result[m] != '-'){ //checks the item to see if it is numeric
char ch2 = result[m]; //makes the number a character
number3 += new String(new char[]{ch2}); //combines the character into a string. For example: '2' + '3' = "23".
++m;}
else {
break;
}}
resultNumber = (Double.parseDouble(number2) * Double.parseDouble(number3)); //"number2" holds the value of the numbers before the operator. Example: This number ----> "3" '*' "23"
equation = equation.replaceAll("(\\d+)", ""); // <---- Line I pulled out earlier that I want to change.
equation = equation.replace("*", resultNumber.toString()); // <----- Line I pulled out earlier
result = equation.toCharArray();
number3 = ""; //erases any number held
number2 = ""; //erases any number held
++n;
break;
}
I'll first suggest two alternate approaches, then answer your question as it stands.
Perhaps beter without regular expressions
I have many doubts about your application. A proper tokenizer (lexer), together with a very simple parser would likely do a better job and give clearer error messages than your code.
Matching all operands
Even if you were to use regular expressions, it might make more sense to match both operands in a single pass. I.e. match (\d+)\s*\*\s*(\d+) to match a multiplication of exactly two numbers. You could first search for a match, then extract the operands from the capturing groups, then compute the resulting value and finally glue together substrings including the result:
// Multiplication of unparenthesized integers
Pattern p = Pattern.compile("(\\d+)\\s*\\*\\s*(\\d+)");
Matcher m = p.matcher(s);
while (m.find()) {
int a = Integer.parseInt(m.group(1));
int b = Integer.parseInt(m.group(2));
s = s.substring(0, m.start(1)) + (a*b) + s.substring(m.end(2));
m.reset(s);
}
Answer to the question as it was phrased in the title
Regarding the exact formulation of your question:
Is there a way to stop a RegEx before a character value and start another one after that character?
If you want a regex to not match after a given character in the input, you can achieve that by a negative look-behind assertion. Likewise, to only match after a given character, you can use a positive look-behind assertion.
So a regex starting in (?<!\*.*) would only match up to the first occurrence of '*', whereas a regex starting in (?<=\*.*) would only match after the first occurrence of that character. Both would have to be compiled using DOTALL, or in a more complicated form like (?<!\*(?:\n|.*)*).
But ensuring that these matches correspond to the math you have in mind would likely be very tricky.

Regex to get first number in string with other characters

I'm new to regular expressions, and was wondering how I could get only the first number in a string like 100 2011-10-20 14:28:55. In this case, I'd want it to return 100, but the number could also be shorter or longer.
I was thinking about something like [0-9]+, but it takes every single number separately (100,2001,10,...)
Thank you.
/^[^\d]*(\d+)/
This will start at the beginning, skip any non-digits, and match the first sequence of digits it finds
EDIT:
this Regex will match the first group of numbers, but, as pointed out in other answers, parseInt is a better solution if you know the number is at the beginning of the string
Try this to match for first number in string (which can be not at the beginning of the string):
String s = "2011-10-20 525 14:28:55 10";
Pattern p = Pattern.compile("(^|\\s)([0-9]+)($|\\s)");
Matcher m = p.matcher(s);
if (m.find()) {
System.out.println(m.group(2));
}
Just
([0-9]+) .*
If you always have the space after the first number, this will work
Assuming there's always a space between the first two numbers, then
preg_match('/^(\d+)/', $number_string, $matches);
$number = $matches[1]; // 100
But for something like this, you'd be better off using simple string operations:
$space_pos = strpos($number_string, ' ');
$number = substr($number_string, 0, $space_pos);
Regexs are computationally expensive, and should be avoided if possible.
the below code would do the trick.
Integer num = Integer.parseInt("100 2011-10-20 14:28:55");
[0-9] means the numbers 0-9 can be used the + means 1 or more times. if you use [0-9]{3} will get you 3 numbers
Try ^(?'num'[0-9]+).*$ which forces it to start at the beginning, read a number, store it to 'num' and consume the remainder without binding.
This string extension works perfectly, even when string not starts with number.
return 1234 in each case - "1234asdfwewf", "%sdfsr1234" "## # 1234"
public static string GetFirstNumber(this string source)
{
if (string.IsNullOrEmpty(source) == false)
{
// take non digits from string start
string notNumber = new string(source.TakeWhile(c => Char.IsDigit(c) == false).ToArray());
if (string.IsNullOrEmpty(notNumber) == false)
{
//replace non digit chars from string start
source = source.Replace(notNumber, string.Empty);
}
//take digits from string start
source = new string(source.TakeWhile(char.IsDigit).ToArray());
}
return source;
}
NOTE: In Java, when you define the patterns as string literals, do not forget to use double backslashes to define a regex escaping backslash (\. = "\\.").
To get the number that appears at the start or beginning of a string you may consider using
^[0-9]*\.?[0-9]+ # Float or integer, leading digit may be missing (e.g, .35)
^-?[0-9]*\.?[0-9]+ # Optional - before number (e.g. -.55, -100)
^[-+]?[0-9]*\.?[0-9]+ # Optional + or - before number (e.g. -3.5, +30)
See this regex demo.
If you want to also match numbers with scientific notation at the start of the string, use
^[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)? # Just number
^-?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)? # Number with an optional -
^[-+]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)? # Number with an optional - or +
See this regex demo.
To make sure there is no other digit on the right, add a \b word boundary, or a (?!\d)
or (?!\.?\d) negative lookahead that will fail the match if there is any digit (or . and a digit) on the right.
public static void main(String []args){
Scanner s=new Scanner(System.in);
String str=s.nextLine();
Pattern p=Pattern.compile("[0-9]+");
Matcher m=p.matcher(str);
while(m.find()){
System.out.println(m.group()+" ");
}
\d+
\d stands for any decimal while + extends it to any other decimal coming directly after, until there is a non number character like a space or letter

Categories