Reputation: 727
I have the following string:
String str = "6,20,9,10,19,11,5,3,1,2";
and i want to replace the exact string ,2
or 1,
to a empty string, avoiding that sub-string ,20
or 11,
were involved into the replacement.
i have this code:
// assuming that substr = ",2" or "1,"
if(str.startsWith(substr+",")){
str = str.replace("^"+substr+",$","");
}
else if(str.contains(","+substr+",")){
str = str.replace("^"+substr+",$","");
}
else if(str.endsWith(","+substr)){
str = str.replace("^,"+substr+"$","");
}
but it seems that i am wrong with the regex. Which regex should i use to resolve it?
Upvotes: 0
Views: 795
Reputation: 159086
I believe the question is "how to remove a value from the list", but only the exact value (e.g. 2 not 12, 13 not 413), and to shorten the list, i.e. to remove the preceding or following comma, if any, but not both.
Short Answer:
String x = Pattern.quote(textToRemove);
Pattern p = Pattern.compile("^"+x+"$|^"+x+",|,"+x+"$|,"+x+"(?=,)");
String output = p.matcher(input).replaceAll(""); // or replaceFirst
Examples:
Input: "6,20,9,10,19,101,5,3,1,2"
Remove "2": "6,20,9,10,19,101,5,3,1" -- last value, don't remove 20
Remove "20": "6,9,10,19,101,5,3,1,2" -- middle value
Remove "1": "6,20,9,10,19,101,5,3,2" -- don't remove 10, 19, or 101
Remove "10": "6,20,9,19,101,5,3,1,2" -- don't remove 101
Remove "6": "20,9,10,19,101,5,3,1,2" -- first value
Remove "77": "6,20,9,10,19,101,5,3,1,2" -- nothing removed
Input: "6"
Remove "6": "" -- only value
Code:
private static void test(String input, String textToRemove) {
String rmv = Pattern.quote(textToRemove);
Pattern p = Pattern.compile("^" + rmv + "$" + // matches only value
"|^" + rmv + "," + // matches first value + ','
"|," + rmv + "$" + // matches ',' + last value
"|," + rmv + "(?=,)"); // matches ',' + middle value (+ ',')
String output = p.matcher(input).replaceAll(""); // or replaceFirst
System.out.printf("Remove %-4s from %-26s: %s%n",
'"' + textToRemove + '"',
'"' + input + '"',
'"' + output + '"');
}
Test:
public static void main(String[] args) throws Exception {
//
test("6,20,9,10,19,101,5,3,1,2", "2" );
test("6,20,9,10,19,101,5,3,1,2", "20");
test("6,20,9,10,19,101,5,3,1,2", "1" );
test("6,20,9,10,19,101,5,3,1,2", "10");
test("6,20,9,10,19,101,5,3,1,2", "6" );
test("6,20,9,10,19,101,5,3,1,2", "77");
test("6" , "6" );
}
Output:
Remove "2" from "6,20,9,10,19,101,5,3,1,2": "6,20,9,10,19,101,5,3,1"
Remove "20" from "6,20,9,10,19,101,5,3,1,2": "6,9,10,19,101,5,3,1,2"
Remove "1" from "6,20,9,10,19,101,5,3,1,2": "6,20,9,10,19,101,5,3,2"
Remove "10" from "6,20,9,10,19,101,5,3,1,2": "6,20,9,19,101,5,3,1,2"
Remove "6" from "6,20,9,10,19,101,5,3,1,2": "20,9,10,19,101,5,3,1,2"
Remove "77" from "6,20,9,10,19,101,5,3,1,2": "6,20,9,10,19,101,5,3,1,2"
Remove "6" from "6" : ""
Upvotes: 0
Reputation: 31339
My answer is: "What are you trying to acheive?"
If you are trying to filter I'd go for String.split(",")
and then filter the items generated in the string array. Eventually I'd join them (if you are not constrained by runtime).
Something like (untested):
String[] splits = myString.split(",");
// ... manipulate splits (filter into a list if you want...)
StringUtils.join(splits, ", "); // possibly replace with array from filtered list
Solving it your way can be tricky. When you try and match an item you eliminate the chance to match it's neighbors. What you need to do is match aggregation.
This is just a start (untested, based on this):
List<String> matches = new ArrayList<String>();
Matcher m = Pattern.compile("(^[12],|,[12],|[12]$)").matcher("1,6,20,9,10,19,11,5,3,1,2");
if (m.find()) {
do {
System.out.println("Matched "+m.group());
matches.add(m.group());
} while (m.find(m.start()+1));
}
for (String match : matches){
System.out.println(match);
}
You can try and profile run-time for both ways and maybe expand my answer later on :-)
Upvotes: 2