简体   繁体   中英

Java replace multiplet characters using regular expression

I am trying to write a String replace method , it works but looks bad using multiple replace methods on same string. Pretty sure I could use a regular expression here.

        List<String>  strng = Collections.singletonList(answer.toString()
                .replace(",", "/")
                .replace("#"", " ")
                .replace("*", "")
                .replace("&", "")
                .replace("]", ""));

I would like to use just 1 replace() or replaceAll() method. in short trying to construct a Regular expression to replace these characters , # * & ]

Simple regex replacement operations do not support conditional replacements in one operation.

With a recent JDK and “preview-features” enabled, you could do as

static final Pattern SPECIAL_CHARS = Pattern.compile("[,#*&\\]]");
List<String> strng = List.of(
    SPECIAL_CHARS.matcher(answer.toString())
        .replaceAll(mr -> switch(mr.group().charAt(0)) {
            case ',' -> "/";
            case '#' -> " ";
            default -> "";
        }));

A Java 8 compatible equivalent would be more elaborated:

static String replaceSpecialChars(String input) {
    Matcher m = SPECIAL_CHARS.matcher(input);
    if(!m.find()) return input;
    StringBuffer sb = new StringBuffer(input.length());
    do {
        String s;
        switch(m.group().charAt(0)) {
            case ',': s = "/"; break;
            case '#': s = " "; break;
            default: s = "";
        }
        m.appendReplacement(sb, s);
    } while(m.find());
    return m.appendTail(sb).toString();
}

While these approaches perform the operation in one go, you'd need a really large input string to draw a benefit from that. Otherwise, your chain of plain (non-regex) replace calls is likely to be more efficient. You could even replace the first two from String to char replacements, ie .replace(',', '/').replace('#', ' ') . Since the other three have the same replacement, they could get replaced by a single .replaceAll("[*&\\\\]]", "") but as said, using the regex engine is not necessarily more efficient than multiple plain text replacement operations.

The last three calls can be replaced with one call by using regex as shown below:

List<String>  strng = Collections.singletonList(answer.toString()
                .replace(",", "/")
                .replace("#", " ")
                .replaceAll("[\\*&\\]]", ""));

The regex, [\\\\*&\\\\]] specifies any of * , & or ] . Learn more about character classes from here .

Demo:

public class Main {
    public static void main(String[] args) {
        String str = "Hello,Hi#Bye*World&Welcome]Good";
        System.out.println(str
                            .replace(",", "/")
                            .replace("#", " ")
                            .replaceAll("[\\*&\\]]", ""));
    }
}

Output:

Hello/Hi ByeWorldWelcomeGood

If you happen to use the Apache Commons library you can use the method replaceChars

replaceChars(String str, String searchChars, String replaceChars)

from the StringUtils class. But just because of the one method to include the library would be superfluous in my opinion.

String str = "foobar,123#xyz*abc&def]";
String res = StringUtils.replaceChars(str, ",#*&]", "/ ");
System.out.println(res);

//output : foobar/123 xyzabcdef 

Divide it into two parts.

  1. Remove all the characters (replacement with an empty string ( "" ). Use String::replaceAll with a Regex defining a set of characters to be removed: answer.replaceAll("[*&\\\\]]", "") .
  2. Have two strings ready containing the characters before replacement and after . Enforce the same length of both strings and a rule that each character is subsituted with exactly one another (according to your question). You can use String[] for this purpose. Iterate through the characters and replace them in the original string.
String[] mapping = {",#", "  "};

// The advantage is the code below remains the same regardles the number or replacements
String newAnswer = IntStream.range(0, mapping[0].length()).boxed().reduce(
    answer.replaceAll("[*&\\]]", ""),
    (str, i) -> str.replace(mapping[0].charAt(i), mapping[1].charAt(i)),
    (l, r) -> l);

As you can see, IntStream.range(int, int) comes handy. Moreover, you can use the removal result itself as an identity of the reduce operation.


Disclaimer: The solution is suitable only for a large set of characters to be removed to avoid repetitions. Otherwise a chain of String::replace is more than suitable.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM