regex pattern won't match anything - java

I'd like my mPattern to match FFF1 or FFF3 strings at least 4 times in a search-string. I've written two pattern versions but neither of those give any matches.
Pattern mPattern = Pattern.compile("(FFF1|FFF3){4,}");
ver2:
Pattern mPattern = Pattern.compile("(FFF1{4,}|FFF3{4,})");
search-string is (example):
0DCB1C992B37173740244875C143D50ACDBA0422CD01D73D3C78F05ED7BBC2B33F9D78A7FFF342C0241C6B56B11EC1867984C20F42A4FAC5B9C0
42220314C006D94E124673CD4CC27FC2FCE12215410F12086BE5A3EDFC6DB2BEB0EAEC6EAAA4BF997FFB3337F914AB1A89C808EA6D338912D72E
99CE11E899999D3AE1092590FB2B71D736DC544B0AFD1035A3FFF340C00E178B62E5BE48C46F04B8EFC106AE3F17DDE08B5FD48672EBEABB216A
8438B6FB3B33BF91D3F3EBFCE14184320532ABA37FFD59BFF6ABAD1AA9AADEE73220679D2C7DDBAB766433A99D8CA752B383067465691750A24A
00F32A5078E29258F6D87A620AFFF342C00A158B22E5BE5944BAE8BA2C54739BE486B719A76DF5FD984D5257DBEAC43B238598EFAB3592DE8DD5

The pattern "(FFF1|FFF3){4,}" will match FFF1 or FFF3 placed adjacent, with a repetition of 4 or more. I guess there can be any characters between multiple occurrences. In that case, use the following regex:
"^(?:.*?(FFF1|FFF3)){4,}.*$"
.*? match any character till the next FFF1 or FFF3, then match FFF1|FFF3. Repeat this sequence 4 or more times (applied on entire non-capturing group).
You can use the above pattern directly with String#matches(String) method. Or, if you are building Pattern and Matcher objects, then just use the following pattern with Matcher#find() method:
"(?:.*?(FFF1|FFF3)){4,}"
Working code:
String str = "..."; // initialize
Pattern mPattern = Pattern.compile("(?x)" + // Ignore whitespace
"(?: " + // Non-capturing group
" .*? " + // 0 or more repetition of any character
" (FFF1|FFF3) " + // FFF1 or FFF3
"){4,} " // Group close. Match group 4 or more times
);
Matcher matcher = mPattern.matcher(str);
System.out.println(matcher.find());

Related

Merge two pattern into one

I need write a pattern to remove currency symbol and comma. eg Fr.-145,000.01
After the pattern matcher should return -145000.01.
The pattern i am using:
^[^0-9\\-]*([0-9\\-\\.\\,]*?)[^0-9\\-]*$
This will return -145,000.01
Then I remove the comma to get -145000.01, I want to ask if that's possible that I change the pattern and directly get -145000.01
String pattern = "^[^0-9\\-]*([0-9\\-\\.\\,]*?)[^0-9\\-]*$";
Pattern p = Pattern.compile(pattern);
Matcher m = p.matcher(str);
if(m.matches()) {
System.out.println(m.group(1));
}
I expect the output could resolve the comma
You can simply it with String.replaceAll() and simpler regex (providing you are expecting the input to be reasonably sane, i.e. without multiple decimal points embedded in the numbers or multiple negative signs)
String str = "Fr.-145,000.01";
str.replaceAll("[^\\d-.]\\.?", "")
If you are going down this route, I would sanity check it by parsing the output with BigDecimal or Double.
One approach would be to just collect our desired digits, ., + and - in a capturing group followed by an optional comma, and then join them:
([+-]?[0-9][0-9.]+),?
Test
import java.util.regex.Matcher;
import java.util.regex.Pattern;
final String regex = "([+-]?[0-9][0-9.]+),?";
final String string = "Fr.-145,000.01\n"
+ "Fr.-145,000\n"
+ "Fr.-145,000,000\n"
+ "Fr.-145\n"
+ "Fr.+145,000.01\n"
+ "Fr.+145,000\n"
+ "Fr.145,000,000\n"
+ "Fr.145\n"
+ "Fr.145,000,000,000.01";
final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final Matcher matcher = pattern.matcher(string);
while (matcher.find()) {
System.out.println("Full match: " + matcher.group(0));
for (int i = 1; i <= matcher.groupCount(); i++) {
System.out.println("Group " + i + ": " + matcher.group(i));
}
}
Demo
String str = "Fr.-145,000.01";
Pattern regex = Pattern.compile("^[^0-9-]*(-?[0-9]+)(?:,([0-9]{3}))?(?:,([0-9]{3}))?(?:,([0-9]{3}))?(\\.[0-9]+)?[^0-9-]*$");
Matcher matcher = regex.matcher(str);
System.out.println(matcher.replaceAll("$1$2$3$4$5"));
Output:
-145000.01
It looks for number with up to 3 commas (Up to 999,999,999,999.99), and replaces it with the digits.
My approach would be to remove all the unnecessary parts using replaceAll.
The unnecessary parts are, apparently:
Any sequence which is not digits or minus at the beginning of the string.
Commas
The first pattern is represented by ^[^\\d-]+. The second is merely ,.
Put them together with an |:
Pattern p = Pattern.compile("(^[^\\d-]+)|,");
Matcher m = p.matcher(str);
String result = m.replaceAll("");
You could 2 capturing groups and make use of repeating matching using the \G anchor to assert the position at the end of the previous match.
(?:^[^0-9+-]+(?=[.+,\d-]*\.\d+$)([+-]?\d{1,3})|\G(?!^)),(\d{3})
In Java
String regex = "(?:^[^0-9+-]+(?=[.+,\\d-]*\\.\\d+$)([+-]?\\d{1,3})|\\G(?!^)),(\\d{3})";
Explanation
(?: Non capturing group
^[^0-9+-]+ Match 1+ times not a digit, + or -
(?= Positive lookahead, assert that what follows is:
[.+,\d-]*\.\d+$ Match 0+ times what is allowed and assert ending on . and 1+ digits
) Close positive lookahead
( Capturing group 1
[+-]?\d{1,3}) Match optional + or - followed by 1-3 digits
| Or
\G(?!^) Assert position at the end of prevous match, not at the start
), Close capturing group 1 and match ,
(\d{3}) Capture in group 2 matching 3 digits
In the replacement use the 2 capturing groups $1$2
See the Regex demo | Java demo

Regex matcher not giving expected result. Not matching number properly

I cannot understand why 2nd group is giving me only 0. I expect 3000. And do point me to a resource where I can understand better.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexMatches {
public static void main( String args[] ) {
// String to be scanned to find the pattern.
String line = "This order was placed for QT3000! OK?";
String pattern = "(.*)(\\d+)(.*)";
// Create a Pattern object
Pattern r = Pattern.compile(pattern);
// Now create matcher object.
Matcher m = r.matcher(line);
if (m.find( )) {
System.out.println("Found value: " + m.group(0) );
System.out.println("Found value: " + m.group(1) );
System.out.println("Found value: " + m.group(2) );//?
System.out.println("Found value: " + m.group(3) );
}else {
System.out.println("NO MATCH");
}
}
}
Precise the pattern, add QT before the \d pattern, or use .*? instead of the first .* to get as few chars as possible.
String pattern = "(.*QT)(\\d+)(.*)";
or
String pattern = "(.*?)(\\d+)(.*)";
will do. See a Java demo.
The (.*QT)(\\d+)(.*) will match and capture into Group 1 any 0+ chars other than line break chars, as many as possible, up to the last occurrence of QT (followed with the subsequent subpatterns), then will match and capture 1+ digits into Group 2, and then will match and capture into Group 3 the rest of the line.
The .*? in the alternative pattern will matchand capture into Group 1 any 0+ chars other than line break chars, as few as possible, up to the first chunk of 1 or more digits.
You may also use a simpler pattern like String pattern = "QT(\\d+)"; to get all digits after QT, and the result will be in Group 1 then (you won't have the text before and after the number).
The * quantifier will try to match as many as possible, because it is a greedy quantifier.
You can make it non-greedy (lazy) by changing it to *?
Then, your regex will become :
(.*?)(\d+)(.*)
And you will match 3000 in the 2nd capturing group.
Here is a regex101 demo

Regular expression with repeating groups in Java Pattern

Lets say I have the following strings:
mya!phaNum3rics-456-456-lll
zzzz-6a6-6a6-lll
vvvv-4-4-lll
These are considered matches because "second" and "third" group repeat, and last group ends with lll. What regex would allows for any character sequence in the second and third "group".
How much different if the following is also considered a match?
zasdfdf-zadezz-6a6-6a6-lll
"third to last group" repeats with "second to last group" and ends with "group" lll.
You need
-([^-]+)-\1-lll$
See the regex demo
- - a hyphen
([^-]+) - Group 1 capturing one or more symbols other than -
- - a hyphen
\1 - a backreference to the text captured into Group 1
-lll - a substring of literal characters
$ - end of string.
Java demo:
String str = "mya!phaNum3rics-456-456-lll";
Pattern ptrn = Pattern.compile("-([^-]+)-\\1-lll$");
Matcher matcher = ptrn.matcher(str);
if (matcher.find()) {
System.out.println(matcher.group(0) + " matched!");
}
A variation of the same regex for use with .matches:
if (str.matches(".*-([^-]+)-\\1-lll")) {
System.out.println(str + " matched!");
}

Java Pattern for Word without Spaces

I am wondering what the regex for a word would be, I can seem to find it anywhere? The string I\m trying to match "Loop-num + 5" and I want to extract the "Loop-num" part. I am unsure what the regex would be to do so.
Pattern pattern = Pattern.compile("(loop-.*)");
Matcher matcher = pattern.matcher("5 * loop-num + 5");
if(matcher.find()){
String extractedString = matcher.group(1);
System.out.println(extractedString);
}
From this I get: "loop-num + 5"
If you really plan to use the regex to match words (entities comprising just letters, optionally split with hyphen(s)), you need to consider the following regex:
\b\pL+(?:-\pL+)*\b
See regex demo
Explanation:
\b - leading word boundary
\pL+ - 1 or more Unicode letters
(?:-\pL+)* - zero or more sequences of...
- - a literal hyphen
\pL+ - 1 or more Unicode letters
\b - trailing word boundary
In Java:
Pattern pattern = Pattern.compile("\\b\\pL+(?:-\\pL+)*\\b", Pattern.UNICODE_CHARACTER_CLASS);
Matcher matcher = pattern.matcher("5 * loop-num + 5");
if(matcher.find()){
String extractedString = matcher.group(0);
System.out.println(extractedString);
}
Note: in case words may include digits (not at the starting positions), you can use \b\pL\w*(?:-\pL\w*)*\b with Pattern.UNICODE_CHARACTER_CLASS. Here, \w will match letters, digits and an underscore.

How to parse a range input in java

I want to parse a range of data (e.g. 100-2000) in Java. Is this code correct:
String patternStr = "^(\\\\d+)-(\\\\d+)$";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(inputStr);
if(matcher.find()){
// Doing some parser
}
Too many backslashes, and you can use matches() without anchors (^$).
String inputStr = "100-2000";
String patternStr = "(\\d+)-(\\d+)";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(inputStr);
if (matcher.matches()) {
System.out.println(matcher.group(1) + " - " + matcher.group(2));
}
As for your question "Is this code correct", all you had to do was wrap the code in a class with a main method and run it, and you'd get the answer: No.
No, you're double (well, quadruple)-escaping the digits.
It should be: "^(\\d+)-(\\d+)$".
Meaning:
Start of input: ^
Group 1: 1+ digit(s): (\\d+)
Hyphen literal: -
Group 2: 1+ digit(s): (\\d+)
End of input: $
Notes
The groups are useful for back-references. Here you're using none, so you can ditch the parenthesis around the \\d+ expressions.
You are parsing the representation of a range in this example.
If you want an actual range class, you can use the [min-max] idiom, where "min" and "max" are numbers, for instance [0-9].
As mentioned by Andreas, you can use String.matches without the Pattern-Matcher idiom and the ^ and $, if you want to match the whole input.

Categories

Resources