Is it possible to match the following in a single regular expression to get the first word, and then a list of the numbers?
this 10 12 3 44 5 66 7 8 # should return "this", "10", "12", ...
another 1 2 3 # should return "another", "1", "2", "3"
EDIT1: My actual data is not this simple, the digits are actually more complex patterns, but for illustration purposes, I've reduced the problem to simple digits, so I do require a regex answer.
The numbers are unknown in length on each line, but all match a simple pattern.
The following only matches "this" and "10":
([\p{Alpha}]+ )(\d+ ?)+?
Dropping the final ? matches "this" and "8".
I had thought that the final group (\d+ ?)+ would do the digit matching multiple times, but it doesn't and I can't find the syntax to do it, if possible.
I can do it in multiple passes, by only searching for the name and latter numbers separately, but was wondering if it's possible in a single expression? (And if not, is there a reason?)
EDIT2: As I mentioned in some of the comments, this was a question in Advent of Code (Day 7, 2020). I was looking to find cleanest solution (who doesn't love a bit of polishing?)
Here's my ultimate solution (kotlin) I used, but spent too long trying to do it in 1 regex, so I posted this question.
val bagExtractor = Regex("""^([\p{Alpha} ]+) bags contain""")
val rulesExtractor = Regex("""([\d]+) ([\p{Alpha} ]+) bag""")
// bagRule is a line from the input
val bag = bagExtractor.find(bagRule)?.destructured!!.let { (n) -> Bag(name = n) }
val contains = rulesExtractor.findAll(bagRule).map { it.destructured.let { (num, bagName) -> Contain(num = num.toInt(), bag = Bag(bagName)) } }.toList()
Rule(bag = bag, contains = contains)
Despite now knowing it can be done in 1 line, I haven't implemented it, as I think it's cleaner in 2.
I think what you are looking for can be achieved by splitting the string on \s+ unless I am missing something.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String str = "this 10 12 3 44 5 66 7 8";
String[] parts = str.split("\\s+");
System.out.println(Arrays.toString(parts));
}
}
Output:
[this, 10, 12, 3, 44, 5, 66, 7, 8]
If you want to select just the alphabetical text and the integer text from the string, you can do it as
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class Main {
public static void main(String[] args) {
String str = "this 10 12 3 44 5 66 7 8";
Matcher matcher = Pattern.compile("(\\b\\p{Alpha}+\\b)|(\\b\\d+\\b)").matcher(str);
while (matcher.find()) {
System.out.println(matcher.group());
}
}
}
Output:
this
10
12
3
44
5
66
7
8
or as
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) {
String str = "this 10 12 3 44 5 66 7 8";
List<String> list = Pattern.compile("(\\b\\p{Alpha}+\\b)|(\\b\\d+\\b)")
.matcher(str)
.results()
.map(MatchResult::group)
.collect(Collectors.toList());
System.out.println(list);
}
}
Output:
[this, 10, 12, 3, 44, 5, 66, 7, 8]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With