'How to replace and split file path in java

I am using below code to replace "\\in" with "\\". "\\in" is the folder name and it can be anything in general.

input "C:\\Users\\Ashish.Gupta\\Documents\\in\\output\\in"

Expected replacedPath = "C:\\Users\\Ashish.Gupta\\Documents\\output\\"

public class Test1 
{
    public static void main(String[] args) 
    {
        String IN = "\\in";
        String SLASH = "\\";
        String path = "C:\\Users\\Ashish.Gupta\\Documents\\in\\output\\in";
        String replacedPath = path.substring(0, path.length())
                                  .replaceAll(IN, SLASH);
        System.out.println("replacedPath" + replacedPath);
        String[] batchIdPath = replacedPath.split(File.separator);
        System.out.println("batchIdPath : " + batchIdPath);
    }
}

Getting below ERROR:

Exception in thread "main" java.util.regex.PatternSyntaxException:
Illegal/unsupported escape sequence near index 1 \in  ^ at
java.base/java.util.regex.Pattern.error(Pattern.java:2028) at
java.base/java.util.regex.Pattern.escape(Pattern.java:2608) at
java.base/java.util.regex.Pattern.atom(Pattern.java:2286) at
java.base/java.util.regex.Pattern.sequence(Pattern.java:2159) at
java.base/java.util.regex.Pattern.expr(Pattern.java:2069) at
java.base/java.util.regex.Pattern.compile(Pattern.java:1783) at
java.base/java.util.regex.Pattern.<init>(Pattern.java:1430) at
java.base/java.util.regex.Pattern.compile(Pattern.java:1069) at
java.base/java.lang.String.replaceAll(String.java:2939) at
Test1.main(Test1.java:14)


Solution 1:[1]

The first parameter in method replaceAll, in class java.lang.String, is a regular expression. To escape a backslash in a regular expression, you need four backslashes, i.e. \\\\. Refer to regex: How to escape backslashes and special characters?.

I understand that you want to remove all directories named in in the source path. If so, then the following code uses string manipulation to achieve that result.
(Note: No need to call method substring before calling replaceAll.)

String IN= "\\\\in";
String SLASH= "\\\\";
String path = "C:\\Users\\Ashish.Gupta\\Documents\\in\\output\\in";
System.out.println("path: " + path);
String replacedPath = path.replaceAll(IN, SLASH);
System.out.println("replacedPath: " + replacedPath);
String[] batchIdPath = replacedPath.split("\\\\");
System.out.println("batchIdPath: " + java.util.Arrays.toString(batchIdPath));

Running above code produces following output:

path: C:\Users\Ashish.Gupta\Documents\in\output\in
replacedPath: C:\Users\Ashish.Gupta\Documents\\output\
batchIdPath: [C:, Users, Ashish.Gupta, Documents, , output]

However, if you are using at least Java 7, then you can use NIO.2 instead of string manipulation.

/*
 * import java.nio.file.Path;
 * import java.nio.file.Paths;
 * import java.util.Iterator;
 */
Path p = Paths.get("C:", "Users", "Ashish.Gupta", "Documents", "in", "output", "in");
System.out.println("p = " + p);
Path bip = p.getRoot();
Iterator<Path> iter = p.iterator();
while (iter.hasNext()) {
    Path next = iter.next();
    if (!"in".equals(next.toString())) {
        bip = bip.resolve(next);
    }
}
System.out.println("bip = " + bip);

Running the above code produces the following output:

p = C:\Users\Ashish.Gupta\Documents\in\output\in
bip = C:\Users\Ashish.Gupta\Documents\output

Solution 2:[2]

Abra's answer works very well.

For completeness' sake, here is a version using the Streams API:

Path p = Path.of("C:", "Users", "Ashish.Gupta", "Documents", "in", "output", "in");
Path bip = StreamSupport.stream(p.spliterator(), false)
    .filter(element -> !"in".equals(element.toString()))
    .reduce(p.getRoot(), Path::resolve);
System.out.println("bip = " + bip);

Solution 3:[3]

The quick answer is to replace replaceAll with replace:

    String replacedPath = path.replace(IN, SLASH);

(btw I've removed the substring call too, I don't know why you had it there in the first place.)

The reason your replaceAll didn't work was that replaceAll uses regex. And there is no such escape \i in regex. You just want to treat the string \in as a normal string to be replaced. The replace method does that (and, yes, it does replace all occurrences).

However, note that this will change, for example, C:\Users\Ashish.Gupta\Documents\in\output\india to C:\Users\Ashish.Gupta\Documents\output\dia which you don't want.

To do this replacement properly, you can use Path and split into into components, and filter out any component named "in":

Path replacedPath = StreamSupport.stream(path.spliterator(), false)
        .filter(not(Path.of("in")::equals))
        .reduce(path.getRoot(), Path::resolve);

This use of Path works just as well in Linux/Unix as it does in Windows.

Edit

To split the path into components instead (as per the question):

Path replacedPath = StreamSupport.stream(path.spliterator(), false)
        .filter(not(Path.of("in")::equals))
        .map(Path::toString)
        .toArray(String[]::new);

Result: String[] {"C:", "Users", "Ashish.Gupta", "Documents", "output"}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 MC Emperor
Solution 3