Salvatore Ucchino
Salvatore Ucchino

Reputation: 727

Java replace exact substring from string

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

Answers (2)

Andreas
Andreas

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

Reut Sharabani
Reut Sharabani

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
  • splits can be replaced by filtered list's toArray

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

Related Questions