Is there a way to use a regex expression with wild cards? Specifically, I have a String phrase and another String target. I would like to use the match method to find the first occurrence of the target in the phrase where the character before and after the target is anything other than a-z.
Updated:
Is there a way to use the String method matches() with the following regex:
"(?<![a-z])" + "hello" + "(?![a-z])";
You can use the regex, "(?<![a-z])" + Pattern.quote(phrase) + "(?![a-z])"
Demo at regex101 with phrase = "hello".
(?<![a-z]): Negative lookbehind for [a-z]
(?![a-z]): Negative lookahead for [a-z]
Java Demo:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Test
String phrase = "hello";
String regex = "(?<![a-z])" + Pattern.quote(phrase) + "(?![a-z])";
Pattern pattern = Pattern.compile(regex);
Stream.of(
"hi hello world",
"hihelloworld"
).forEach(s -> {
Matcher matcher = pattern.matcher(s);
System.out.print(s + " => ");
if(matcher.find()) {
System.out.println("Match found");
}else {
System.out.println("No match found");
}
});
}
}
Output:
hi hello world => Match found
hihelloworld => No match found
In case you want the full-match, use the regex, .*(?<![a-z]) + Pattern.quote(phrase) +(?![a-z]).* as demonstrated at regex101.com. The pattern, .* means any character any number of times. The rest of the patterns are already explained above. The presence of .* before and after the match will ensure covering the whole string.
Java Demo:
import java.util.regex.Pattern;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
// Test
String phrase = "hello";
String regex = ".*(?<![a-z])" + Pattern.quote(phrase) + "(?![a-z]).*";
Stream.of(
"hi hello world",
"hihelloworld"
).forEach(s -> System.out.println(s + " => " + (s.matches(regex) ? "Match found" : "No match found")));
}
}
Output:
hi hello world => Match found
hihelloworld => No match found
I have this code:
String line = "There were bear#67 with dog#1323 and cat#5475 in the forest";
String pattern = ".* ([^ ]+)#(\\d{4}).*";
Pattern r = Pattern.compile(pattern);
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) );
} else {
System.out.println("NO MATCH");
}
It prints
Found value: There were bear#67 with dog#1323 and cat#5475 in the forest
Found value: cat
Found value: 5475
However I need to get all matches as ArrayList:
dog#1323, cat#5475
How would I do that?
Converting my comment to answer so that solution is easy to find for future visitors.
You may use a simpler regex without any capture group:
[^ ]+#\\d{4}
Which matches 1+ of a non-space characters before # and then 4 digits.
Code:
final String line = "There were bear#67 with dog#1323 and cat#5475 in the forest";
final Pattern r = Pattern.compile("[^ ]+#\\d{4}");
Matcher m = r.matcher(line);
List<String> arr = new ArrayList<>();
while (m.find( )) {
arr.add(m.group());
}
System.out.println(arr);
//=> [dog#1323, cat#5475]
If you want to put all matches in a list, then you have to create one like this :
String pattern = "[^ ]+#\\d{4}"; // or "[a-z]+#\\d{4}" if you want only alphabets
//..
List<String> values = new ArrayList<>();
while (m.find()) {
values.add(m.group(0));
}
Note: you need to use while loop and not an if statement(which match only one value).
Output
[dog#1323, cat#5475]
Using the Stream API, you can do it with a single statement.
Demo:
import java.util.List;
import java.util.regex.MatchResult;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
public class Main {
public static void main(String[] args) {
List<String> list = Pattern.compile("(?<=\\s?)\\p{L}+#\\d{4}")
.matcher("There were bear#67 with dog#1323 and cat#5475 in the forest")
.results()
.map(MatchResult::group)
.collect(Collectors.toList());
System.out.println(list);
}
}
Output:
[dog#1323, cat#5475]
Explanation of the regex:
(?<=\s?) specifies the positive lookbehind for optional whitespace
\p{L}+ specifies one or more letter(s)
# specifies the char, #
\d{4} specifies 4 digits
I have this string:
values="[72, 216, 930],[250],[72],[228, 1539],[12]";
am trying to combine two patterns in order to get the last number in first [] type and the number in the second [] type.
pattern="\\, ([0-9]+)\\]|\\[([0-9]+)\\]"
But it outputs null:
930, null, null, 1539, null
How do I solve this problem?
Here, we might not want to bound it from the left, and simply use the ] from right, then we swipe to left and collect our digits, maybe similar to this expression:
([0-9]+)\]
Graph
This graph shows how it would work:
If you like, we can also bound it from the left, similar to this expression:
([\[\s,])([0-9]+)(\])
Graph
This graph shows how the second one would work:
Try this.
import java.util.regex.Matcher;
import java.util.regex.Pattern;
final String regex = ", ([0-9]+)]";
final String string = "[72, 216, 930],[250],[72],[228, 1539],[12]";
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));
}
}
Output:
Full match: , 930]
Group 1: 930
Full match: , 1539]
Group 1: 1539
package Sample;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class StackOverFlow{
final static String regex = "\\d*]";
final static String string = "[72, 216, 930],[250],[72],[228, 1539],[12]";
final static Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
final static Matcher matcher = pattern.matcher(string);
public static void main(String[] args) {
while (matcher.find()) {
String val = matcher.group(0).replace("]", "");
System.out.println(val);
}
}
}
output
930
250
72
1539
12
To make sure that the data is actually in between square brackets, you could use a capturing group, start the match with [ and end the match with ]
\[(?:\d+,\h+)*(\d+)]
In Java
\\[(?:\\d+,\\h+)*(\\d+)]
\[ Match [
(?:\d+,\h+)* Repeat 0+ times matching 1+ digit, comma and 1+ horizontal whitespace chars
(\d+) Capture in group 1 matching 1+ digit
] Match closing square bracket
Regex demo | Java demo
For example:
String regex = "\\[(?:\\d+,\\h+)*(\\d+)]";
String string = "[72, 216, 930],[250],[72],[228, 1539],[12]";
Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
Matcher matcher = pattern.matcher(string);
while (matcher.find()) {
System.out.println(matcher.group(1));
}
Result:
930
250
72
1539
12
It seems like for a structure such as this, it's likely beneficial to parse the whole thing into memory, then index into the elements you're particularly interested in to your heart's content. Should the structure change unexpectedly/dynamically, you won't need to rewrite your regex, just index as needed as many times as you wish:
import java.util.*;
class Main {
public static void main(String[] args) {
String values = "[72, 216, 930],[250],[72],[228, 1539],[12]";
String[] data = values.substring(1, values.length() - 1).split("\\]\\s*,\\s*\\[");
ArrayList<String[]> result = new ArrayList<>();
for (String d : data) {
result.add(d.split("\\s*,\\s*"));
}
System.out.println(result.get(0)[result.get(0).length-1]); // => 930
System.out.println(result.get(1)[0]); // => 250
}
}
Problem is last one character never gets matched.
When I tried displaying using group ,it shows all match except last character.
Its same in all cases.
Below is the code and its o/p.
package mon;
import java.util.*;
import java.util.regex.*;
class HackerRank {
static void Pattern(String text) {
String p="\\d{1,2}|(0|1)\\d{2}|2[0-4]\\d|25[0-5]";
String pattern="(("+p+")\\.){3}"+p;
Pattern pi=Pattern.compile(pattern);
Matcher m=pi.matcher(text);
// System.out.println(m.group());
if(m.find() && m.group().equals(text))
System.out.println(m.group()+"true");
else
System.out.println(m.group()+" false");
}
public static void main(String[] args) {
Scanner sc=new Scanner(System.in);
while(sc.hasNext()) {
Pattern(sc.next());
}
sc.close();
}
}
I/P:000.12.12.034;
O/P:000.12.12.03 false
You should properly group the alternatives inside the octet pattern:
String p="(?:\\d{1,2}|[01]\\d{2}|2[0-4]\\d|25[0-5])";
// ^^^ ^
Then build the patter like
String pattern = p + "(?:\\." + p + "){3}";
It will become a bit more efficient. Then, use matches to require a full string match:
if(m.matches()) {...
See a Java demo:
String p="(?:\\d{1,2}|[01]\\d{2}|2[0-4]\\d|25[0-5])";
String pattern = p + "(?:\\." + p + "){3}";
String text = "192.156.34.56";
// System.out.println(pattern); => (?:\d{1,2}|[01]\d{2}|2[0-4]\d|25[0-5])(?:\.(?:\d{1,2}|[01]\d{2}|2[0-4]\d|25[0-5])){3}
Pattern pi=Pattern.compile(pattern);
Matcher m=pi.matcher(text);
if(m.matches())
System.out.println(m.group()+" => true");
else
System.out.println("False"); => 192.156.34.56 => true
And here is the resulting regex demo.
I am missing something basic here. I have this regex (.*)=\1 and I am using it to match 100=100 and its failing. When I remove the back reference from the regex and continue to use the capturing group, it shows that the captured group is '100'. Why does it not work when I try to use the back reference?
package test;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexTest {
public static void main(String[] args) {
String eqPattern = "(.*)=\1";
String input[] = {"1=1"};
testAndPrint(eqPattern, input); // this does not work
eqPattern = "(.*)=";
input = new String[]{"1=1"};
testAndPrint(eqPattern, input); // this works when the backreference is removed from the expr
}
static void testAndPrint(String regexPattern, String[] input) {
System.out.println("\n Regex pattern is "+regexPattern);
Pattern p = Pattern.compile(regexPattern, Pattern.CASE_INSENSITIVE);
boolean found = false;
for (String str : input) {
System.out.println("Testing "+str);
Matcher matcher = p.matcher(str);
while (matcher.find()) {
System.out.println("I found the text "+ matcher.group() +" starting at " + "index "+ matcher.start()+" and ending at index "+matcher.end());
found = true;
System.out.println("Group captured "+matcher.group(1));
}
if (!found) {
System.out.println("No match found");
}
}
}
}
When I run this, I get the following output
Regex pattern is (.*)=\1
Testing 100=100
No match found
Regex pattern is (.*)=
Testing 100=100
I found the text 100= starting at index 0 and ending at index 4
Group captured 100 -->If the group contains 100, why doesnt it match when I add \1 above
?
You have to escape the pattern string.
String eqPattern = "(.*)=\\1";
I think you need to escape the backslash.
String eqPattern = "(.*)=\\1";