java regex with boundaries - java

I need to search for words using a regular expression. Currently, I am using
String word = words.toLowerCase().replaceAll("[\\W]", "\\\\$0");
Pattern pattern = Pattern.compile("(?i)\\b(" + word + ")\\b");
where word is the regular word or with the wild card.
So far this expression works fine with regular words. But it fails to find a match using the wild card. For example, if I want to find all the words like matches, matched, matchstick, etc, using match(\w*), that should technically work, but it fails with the above expression ( with boundaries). How can I make it work?

If your only problem is restoring \w* or \w+ pattern in a regular expression use
String word = words.replaceAll("\\W", "\\\\$0").replaceAll("\\\\{2}(w)\\\\?([*+])", "\\\\$1$2");
.toLowerCase() is not necessary, you are using (?i) case insensitive flag option.

Related

Java Regular Expression: matching a customized Hashtag pattern with a lookahead/lookbehind condition

I am currently learning how to write regular expressions in Java by trying to match simple Hashtag pattern. The Hashtags obey the following conditions:
It starts with a hashtag: #
It has to contain at least 1 letter: [a-zA-Z]
It can contain any of the characters from the class [a-zA-Z0-9_]
It cannot be preceded by a character of the class [a-zA-Z0-9_]
Based on this, I thought that the correct regular expression is:
PATTERN = "(?<![a-zA-Z0-9_])#(?=.*[a-zA-Z])[a-zA-Z0-9_]+"
Here I'm using a lookahead (?=.*[a-zA-Z]) to make sure Condition 2 holds and using a lookbehind (?<![a-zA-Z0-9_]) to make sure Condition 4 holds. I'm less certain about ending with a +.
This works on simple test cases but fails on complicated ones such as:
String text = "####THIS_IS_A_HASHTAG; ;#This_1_2...#12_and_this but not #123 or #this# #or#that";
where does not match #THIS_IS_A_HASHTAG, #This_1_2 and 12_and_this
Could someone explain what I'm doing wrong?
This lookahead:
(?=.*[a-zA-Z])
may produce wrong results for the cases when input is like this:
####12345...#12_and_this
by giving you 2 matches #12345 and #12_and_this. Whereas as per your rules only 2nd should be valid match.
To fix this you can use this regex:
(?<![a-zA-Z0-9_])#(?=[0-9_]*[a-zA-Z])[a-zA-Z0-9_]+
Where lookahead (?=[0-9_]*[a-zA-Z]) means assert presence of a letter after # with optional presence of a digit or underscore in between.
Here is a regex demo for you
How about this?
(example here)
String text = "####THIS_IS_A_HASHTAG;;;#This_1_2...#12_and_this ";
String regex = "#[A-Za-z0-9_]+";
Matcher m = Pattern.compile(regex).matcher(text);
while (m.find()) {
System.out.println(m.group());
}
It looks like it meets your criteria as stated:
#THIS_IS_A_HASHTAG
#This_1_2
#12_and_this

How can I obtain what .* matched in a regular expression?

I have thousands of different regular expressions and they look like this:
^Mozilla.*Android.*AppleWebKit.*Chrome.*OPR\/([0-9\.]+)
How do I obtain those substrings that match the .* in the regex? For example, for the above regex, I would get four substrings for four different .*s. In addition, I don't know in advance how many .*s there are, even though I can possibly find out by doing some simple operation on the given regex string, but that would impose more complexity on the program. I process a fairly big amount of data, so really focus on the efficiency here.
Replace the .*s with (.*)s and use matcher.group(n). For instance:
Pattern p = Pattern.compile("1(.*)2(.*)3");
Matcher m = p.matcher("1abc2xyz3");
m.find();
System.out.println(m.group(2));
xyz
Notice how the match of the second (.*) was returned (since m.group(2) was used).
Also, since you mentioned you won't know how many .*s your regex will contain, there is a matcher.groupCount() method you can use, if the only capturing groups in your regex will indeed be (.*)s.
For your own enlightenment, try reading about capturing groups.
How do I get those substrings that match the .* in the regex? For example, for the above regex, I would get four substrings for four different DOT STAR.
Use groups: (.*)
I addition, I don't know in advance how many DOT STARs there are
Build your regex string, then replace .* with (.*):
String myRegex = "your regex here";
myRegex = myRegex.replace(".*","(.*)");
even though I can possible find out about that by doing some simple operation on the given regex string, but that would impose more complexity on the program
If you don't know how the regex is made and the regex is not built by your application, the only way is to process it after you have it. If you are building the regex, then append (.*) to the regex string instead of appending .*

Match word in String in Java

I'm trying to match Strings that contain the word "#SP" (sans quotes, case insensitive) in Java. However, I'm finding using Regexes very difficult!
Strings I need to match:
"This is a sample #sp string",
"#SP string text...",
"String text #Sp"
Strings I do not want to match:
"Anything with #Spider",
"#Spin #Spoon #SPORK"
Here's what I have so far: http://ideone.com/B7hHkR .Could someone guide me through building my regexp?
I've also tried: "\\w*\\s*#sp\\w*\\s*" to no avail.
Edit: Here's the code from IDEone:
java.util.regex.Pattern p =
java.util.regex.Pattern.compile("\\b#SP\\b",
java.util.regex.Pattern.CASE_INSENSITIVE);
java.util.regex.Matcher m = p.matcher("s #SP s");
if (m.find()) {
System.out.println("Match!");
}
(edit: positive lookbehind not needed, only matching is done, not replacement)
You are yet another victim of Java's misnamed regex matching methods.
.matches() quite unfortunately so tries to match the whole input, which is a clear violation of the definition of "regex matching" (a regex can match anywhere in the input). The method you need to use is .find().
This is a braindead API, and unfortunately Java is not the only language having such misguided method names. Python also pleads guilty.
Also, you have the problem that \\b will detect on word boundaries and # is not part of a word. You need to use an alternation detecting either the beginning of input or a space.
Your code would need to look like this (non fully qualified classes):
Pattern p = Pattern.compile("(^|\\s)#SP\\b", Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher("s #SP s");
if (m.find()) {
System.out.println("Match!");
}
You're doing fine, but the \b in front of the # is misleading. \b is a word boundary, but # is already not a word character (i.e. it isn't in the set [0-9A-Za-z_]). Therefore, the space before the # isn't considered a word boundary. Change to:
java.util.regex.Pattern p =
java.util.regex.Pattern.compile("(^|\\s)#SP\\b",
java.util.regex.Pattern.CASE_INSENSITIVE);
The (^|\s) means: match either ^ OR \s, where ^ means the beginning of your string (e.g. "#SP String"), and \s means a whitespace character.
The regular expression "\\w*\\s*#sp\\w*\s*" will match 0 or more words, followed by 0 or more spaces, followed by #sp, followed by 0 or more words, followed by 0 or more spaces. My suggestion is to not use \s* to break words up in your expression, instead, use \b.
"(^|\b)#sp(\b|$)"

Regular expression (three types of a word)?

I am new to regular expressions and need some help.
I have these sentences:
this is a-word
a word this is
aword is this
AWord is this
A-WORD is this
I'd like to know if the word a word or a-word or aword or AWord or A-WORD is in the sentence.
I tried this:
String sentence = "AWord is this";
String regex = "(a(\\s,'-','')word)\\i";
if (sentence.matches( regex)){
.....
}
Try
a[^\w]?word
This will match any a followed by anything but a char, followed by word.
To match a narrower range of strings use [-\s]
Put (?i) at the beginning of the regex to make it case insensitive
(?i)a[^\w]?word
(reference, search here for other ways to search strings in a case insensitive way)
and remember to escape the \ to \\
The "safest" way is however to use this one
((a word)|(a-word)|(aword)|(AWord)|(A-WORD))
because it will match exactly what you need (if you know the exact domain of what you are looking for)
Try this : (?:a[ -]?word|A-?W(?:ord|ORD))
It will match all words you listed

regex to find substring between special characters

I am running into this problem in Java.
I have data strings that contain entities enclosed between & and ; For e.g.
&Text.ABC;, &Links.InsertSomething;
These entities can be anything from the ini file we have.
I need to find these string in the input string and remove them. There can be none, one or more occurrences of these entities in the input string.
I am trying to use regex to pattern match and failing.
Can anyone suggest the regex for this problem?
Thanks!
Here is the regex:
"&[A-Za-z]+(\\.[A-Za-z]+)*;"
It starts by matching the character &, followed by one or more letters (both uppercase and lower case) ([A-Za-z]+). Then it matches a dot followed by one or more letters (\\.[A-Za-z]+). There can be any number of this, including zero. Finally, it matches the ; character.
You can use this regex in java like this:
Pattern p = Pattern.compile("&[A-Za-z]+(\\.[A-Za-z]+)*;"); // java.util.regex.Pattern
String subject = "foo &Bar; baz\n";
String result = p.matcher(subject).replaceAll("");
Or just
"foo &Bar; baz\n".replaceAll("&[A-Za-z]+(\\.[A-Za-z]+)*;", "");
If you want to remove whitespaces after the matched tokens, you can use this re:
"&[A-Za-z]+(\\.[A-Za-z]+)*;\\s*" // the "\\s*" matches any number of whitespace
And there is a nice online regular expression tester which uses the java regexp library.
http://www.regexplanet.com/simple/index.html
You can try:
input=input.replaceAll("&[^.]+\\.[^;]+;(,\\s*&[^.]+\\.[^;]+;)*","");
See it

Categories