Java doesn't parse Regular Expressions in the same way as Python for a small set of cases. In this particular case the nested ['s were causing problems. In Python you don't need to escape any nested [ but you do need to do that in Java.
The original RegEx (for Python):
/(\\.|[^[/\\\n]|\[(\\.|[^\]\\\n])*])+/([gim]+\b|\B)
The fixed RegEx (for Java and Python):
/(\\.|[^\[/\\\n]|\[(\\.|[^\]\\\n])*\])+/([gim]+\b|\B)
Answer from Vineet on Stack OverflowJava doesn't parse Regular Expressions in the same way as Python for a small set of cases. In this particular case the nested ['s were causing problems. In Python you don't need to escape any nested [ but you do need to do that in Java.
The original RegEx (for Python):
/(\\.|[^[/\\\n]|\[(\\.|[^\]\\\n])*])+/([gim]+\b|\B)
The fixed RegEx (for Java and Python):
/(\\.|[^\[/\\\n]|\[(\\.|[^\]\\\n])*\])+/([gim]+\b|\B)
The obvious difference b/w Java and Python is that in Java you need to escape a lot of characters.
Moreover, you are probably running into a mismatch between the matching methods, not a difference in the actual regex notation:
Given the Java
String regex, input; // initialized to something
Matcher matcher = Pattern.compile( regex ).matcher( input );
- Java's
matcher.matches()(alsoPattern.matches( regex, input )) matches the entire string. It has no direct equivalent in Python. The same result can be achieved by usingre.match( regex, input )with aregexthat ends with$. - Java's
matcher.find()and Python'sre.search( regex, input )match any part of the string. - Java's
matcher.lookingAt()and Python'sre.match( regex, input )match the beginning of the string.
For more details also read Java's documentation of Matcher and compare to the Python documentation.
Since you said that isn't the problem, I decided to do a test: http://ideone.com/6w61T
It looks like java is doing exactly what you need it to (group 0, the entire match, doesn't contain the ;). Your problem is elsewhere.
As suggested by Wiktor in the comments, you could use (?U) to turn on the flag UNICODE_CHARACTER_CLASS. While this does allow matching äöa, this still doesn't match m². That's because UNICODE_CHARACTER_CLASS with \w doesn't recognize ² as a valid alphanumeric character. As a replacement for \w, you can use [\pN\pL_]. This matches Unicode numbers \pN and Unicode letters \pL (plus _). The \pN Unicode character class includes the \pNo character class, which includes the Latin 1 Supplement - Latin-1 punctuation and symbols character class (it includes ²³¹). Alternatively, you could just add the \pNo Unicode character class to a character class with \w. This means the following regular expressions correctly match your strings:
[\pN\pL_]{2,} # Matches any Unicode number or letter, and underscore
(?U)[\w\pNo]{2,} # Uses UNICODE_CHARACTER_CLASS so that \w matches Unicode.
# Adds \pNo to additionally match ²³¹
So why doesn't \w match ² in Java but it does in Python?
Java's interpretation
Looking at OpenJDK 8-b132's Pattern implementation, we get the following information (I removed information irrelevant to answering the question):
Unicode support
The following Predefined Character classes and POSIX character classes are in conformance with the recommendation of Annex C: Compatibility Properties of Unicode Regular Expression, when
UNICODE_CHARACTER_CLASSflag is specified.
\wA word character:[\p{Alpha}\p{gc=Mn}\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}\p{IsJoin_Control}]
Great! Now we have a definition for \w when the (?U) flag is used. Plugging these Unicode character classes into this amazing tool will tell you exactly what each of these Unicode character classes match. Without making this post super long, I'll just go ahead and tell you that neither of the following classes matches ²:
\p{Alpha}\p{gc=Mn}\p{gc=Me}\p{gc=Mc}\p{Digit}\p{gc=Pc}\p{IsJoin_Control}
Python's interpretation
So why does Python match ²³¹ when the u flag is used in conjunction with \w? This one was very difficult to track down, but I went digging into Python's source code (I used Python 3.6.5rc1 - 2018-03-13). After removing a lot of the fluff for how this gets called, basically the following happens:
\wis defined asCATEGORY_UNI_WORD, which is then prefixed withSRE_.SRE_CATEGORY_UNI_WORDcallsSRE_UNI_IS_WORD(ch)SRE_UNI_IS_WORDis defined as(SRE_UNI_IS_ALNUM(ch) || (ch) == '_').SRE_UNI_IS_ALNUMcallsPy_UNICODE_ISALNUM, which is, in turn, defined as(Py_UNICODE_ISALPHA(ch) || Py_UNICODE_ISDECIMAL(ch) || Py_UNICODE_ISDIGIT(ch) || Py_UNICODE_ISNUMERIC(ch)).- The important one here is
Py_UNICODE_ISDECIMAL(ch), defined asPy_UNICODE_ISDECIMAL(ch) _PyUnicode_IsDecimalDigit(ch).
Now, let's take a look at the method _PyUnicode_IsDecimalDigit(ch):
int _PyUnicode_IsDecimalDigit(Py_UCS4 ch)
{
if (_PyUnicode_ToDecimalDigit(ch) < 0)
return 0;
return 1;
}
As we can see, this method returns 1 if _PyUnicode_ToDecimalDigit(ch) < 0. So what does _PyUnicode_ToDecimalDigit look like?
int _PyUnicode_ToDecimalDigit(Py_UCS4 ch)
{
const _PyUnicode_TypeRecord *ctype = gettyperecord(ch);
return (ctype->flags & DECIMAL_MASK) ? ctype->decimal : -1;
}
Great, so basically, if the character's UTF-32 encoded byte has the DECIMAL_MASK flag this will evaluate to true and a value greater than or equal to 0 will be returned.
UTF-32 encoded byte value for ² is 0x000000b2 and our flag DECIMAL_MASK is 0x02. 0x000000b2 & 0x02 evaluates to true and so ² is deemed to be a valid Unicode alphanumeric character in python, thus \w with u flag matches ².
There is one more step left: you need to specify that \w includes unicode characters too. Pattern.UNICODE_CHARACTER_CLASS for the rescue:
Pattern regex = Pattern.compile("(?u)\\b\\w\\w+\\b", Pattern.UNICODE_CHARACTER_CLASS);
// ^^^^^^^^^^
Matcher matcher = regex.matcher("this is the document.!? äöa m²");
while(matcher.find()) {
String match = matcher.group();
System.out.println(match);
}
Java regex matcher not matching - Stack Overflow
2023 Day 2 Part A [Java] regex pattern not matching
Python regex not working like it should - Stack Overflow
Simple java regex not matching - Stack Overflow
You first need to do
matcher.find()
to trigger the actual search. Usually like this:
Pattern pattern = Pattern.compile("(browse/)(.*)(\">)");
Matcher matcher = pattern.matcher(match);
if (matcher.find())
return matcher.group(1);
You should probably be using a different regex, though:
Pattern pattern = Pattern.compile("browse/([^<>\"]*)\">");
will be safer and more efficient (and provide the correct value in group number 1).
You have to call Matcher.find() or Matcher.matches() before you extract groups.
In your exact case you should call Matcher.find(), since your regex won't match against the entire input, which is what Matcher.matches() checks for.
First time posting here, let me know if I need to edit post to conform to any rules. My issue is that I'm trying to match regex pattern to separate out the number of cubes drawn and its color but my Matcher object seems to not be returning any matches so it's throwing a no match found exception when I try to call digitMatcher.group(). I have tested my regex pattern on sites like regexr and it seems to pass there but it's not working for some reason here. I use the same type of regex on day one and it work there so I'm not sure where my regex pattern is failing here. I'm talking about specifically in my isGameValid() method where I create a matcher base on a pattern I made above. Through debugging I know that I separated the string color pairing correctly and that my Matcher object has the correct regex pattern, it's just not matching for some reason. Any help would be appreciated. Code below:
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Scanner;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import static java.lang.Integer.parseInt;
import static java.lang.Integer.sum;
public class dayTwoA {
public static final Map<String, Integer> map = Map.of( // Mapping of digits to their letter spelling.
"red", 12,
"green", 13,
"blue", 14
);
public static final Pattern colorPattern = Pattern.compile("blue|green|red");
public static final Pattern digitPattern = Pattern.compile("[0-9]|[0-9][0-9]");
public static int gameID = 0;
public static void main(String[] args) throws FileNotFoundException {
int sumGamesID = 0; // Sum of all the game ID.
// Create a scanner to get input from file.
Scanner inputFile = new Scanner(new File("src/dayTwoData.txt"));
// Parse file for data.
while (inputFile.hasNextLine()) {
String inputLine = inputFile.nextLine(); // Grab next line of input.
if (isGameValid(inputLine)) {
sumGamesID += gameID;
};
}
System.out.println("The sum of the ID of the games is " + sumGamesID);
}
private static boolean isGameValid(String inputLine) {
String gameDraws = inputLine.substring(inputLine.indexOf(":") + 1);
gameID++; // Increment game ID.
StringTokenizer separateDraw = new StringTokenizer(gameDraws, ";");
while (separateDraw.hasMoreTokens()) {
String draw = separateDraw.nextToken();
StringTokenizer numColor = new StringTokenizer(draw, ",");
while (numColor.hasMoreTokens()) {
String numColorPair = numColor.nextToken();
Matcher digitMatcher = digitPattern.matcher(numColorPair);
int numCubes = parseInt(digitMatcher.group());
Matcher colorMatcher = colorPattern.matcher(numColorPair);
String color = colorMatcher.group();
System.out.println(numCubes + "-" + colorMatcher.group());
if (numCubes > map.get(color)) {
return false;
}
System.out.println(numColorPair);
}
}
return true;
}
}Regex expressions are always difficult to read. Try an online Regex tester. This will probably give you some more information about what is wrong and you can try different inputs and expressions. These are my favorites:
- http://www.regexplanet.com/advanced/java/index.html
- https://regex101.com/#python
In your case I think you have added some extra space characters to the regex that should not be there. Space also counts as a character that needs to match.
I would also add parentheses around the expressions that are separated with |. Sometimes it is hard to know what parts are used when inserting a | character.
Like this:
'(?:^(?:[A-z][a-z]{2}[ ][0-9]{1,2}[ ][\d]{2}[:][\d]{2}[:][\d]{2}))|(?:li146-252)|(?:[0-9]{5})|(?:Failed password for invalid)'
I think you don't want to use alterations "|" for parts of your regex, instead, you should define substrings () for all parts you want to extract from the string. What do you want to extract exactly? Other than that, avoid empty spaces and define spaces as "\s", i am not sure if [ ] is a correct substitute.
There is an quick example of what you could (i don't know what you really need) get (no optimization though):
([\D]{2,3}\s\d{2}\s\d{2}:\d{2}:\d{2})\s(li146-252)\s(sshd\[\d+\]):\s[\D\s]+((\d{1,3}\.){3}\d{1,3})
I'm stumped with a regex problem.
I've tested this regex on multiple test sites (pythex.org and regex101.com), and all of them show that the regex is good. However, when Python runs the test, my match object (m) is None.
Regex: (.{0,25}\b)(?:humans|human)(\b.{0,25})
Text to search: Additional text Additional text Additional text Additional text This is a test - Testing response to the word human nested inside a paragraph with at least 25 characters on either side of the trigger word Additional text Additional text Additional text
Actual relevant code:
m = re.search("(.{0,25}\b)(?:humans|human)(\b.{0,25})", comment.body, re.IGNORECASE)
print(m)
if m:
#stuff that doesn't happen because m = NoneAnd when I run it, I get "None" in my output.
I even force updated all my libs. I don't know why this is coming up empty.
And yes comment.body is not blank (and PRAW is up to date)
Welcome to Java's misnamed .matches() method... It tries and matches ALL the input. Unfortunately, other languages have followed suit :(
If you want to see if the regex matches an input text, use a Pattern, a Matcher and the .find() method of the matcher:
Pattern p = Pattern.compile("[a-z]");
Matcher m = p.matcher(inputstring);
if (m.find())
// match
If what you want is indeed to see if an input only has lowercase letters, you can use .matches(), but you need to match one or more characters: append a + to your character class, as in [a-z]+. Or use ^[a-z]+$ and .find().
[a-z] matches a single char between a and z. So, if your string was just "d", for example, then it would have matched and been printed out.
You need to change your regex to [a-z]+ to match one or more chars.
You need to call Matcher#find() to actually get a match:
Pattern p = Pattern.compile("([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)-([0-9]+)");
Matcher matcher = p.matcher("1-1-3-1-4");
if (matcher.find()) {
System.out.println(matcher.group(0))
}
If you were expecting multiple matches, you could use a while loop instead of an if statement.
Also note that you actually have five capture groups in your patterns. Capture groups are denoted by placing a portion of the pattern in parentheses. If you don't intend/need to capture the five separated numbers in your pattern individually, then you can consider telling the regex engine not to capture them, e.g. use this:
Pattern p = Pattern.compile("(?:[0-9]+)-(?:[0-9]+)-(?:[0-9]+)-(?:[0-9]+)-(?:[0-9]+)");
Demo
In Java regex index or study methods are used to return Matcher class matches:
if (matcher.matches()) {
System.out.println(matcher.group(0));
}
In the example above, the matches() "study" method attempts to match the entire region against the given pattern. Which method you use is generally indicative of what/how you want to match.
matches()
Attempts to match the entire region against the pattern.
find()
Attempts to find the next subsequence of the input sequence that matches the pattern.
Study methods review the input string and return a Boolean indicating whether or not the pattern is found
↳ http://docs.oracle.com/javase/tutorial/essential/regex/matcher.html
Java's String.matches function matches the entire string, instead of just one part. That means, it is roughly equivalent to the regex ^[^=]=[^=]$, so both returns false. To build a regex working equivalent to yours, you should use:
str.matches("(?s).*[^=]=[^=].*")
(The (?s) ensures the . matches everything.)
Alternatively, you could build a Pattern and use Matcher for greater flexibility. This is what String.matches uses.
final Pattern p = Pattern.compile("[^=]=[^=]");
final Matcher m = p.matcher(str);
return m.find();
You must add either * or + to your regexp:
str.matches("[^=]+=[^=]+")
This is needed, because string.matches() is anchored by default. This is equivalent to ^[^=]+=[^=]+$ and means that it must match the whole string and not only a part of it.