Making sure a path string is a valid java path string - java

This is how i try to make sure a path given in a property file is a valid java path (with \\ instead of \) :
String path = props.getProperty("path");
if (path.length()>1) path=path.replaceAll("\\\\", "\\");
if (path.length()>1) path=path.replaceAll("\\", "\\\\");
in the first replace im making sure that if the path already valid (has \\ instead of \) then it wont get doubled to \\\\ instead of \\ in the second replace...
anyway i get this weird exception :
java.lang.StringIndexOutOfBoundsException: String index out of range: 1
at java.lang.String.charAt(Unknown Source)
at java.util.regex.Matcher.appendReplacement(Unknown Source)
at java.util.regex.Matcher.replaceAll(Unknown Source)
at java.lang.String.replaceAll(Unknown Source)
at com.hw.Launcher.main(Launcher.java:56)
can anyone tell why?!

replaceAll expects RegExes, use replace instead.
You can find the JavaDocs here

If you want to be sure the path is valid, how about trying
File f = new File("c:\\this\\that");
f.getCanonicalPath();
The File class is made for taking apart paths. It's probably the best way to verify that a path is valid.

(Let me spell it out for newbies too.)
If you have a text file or a String, normally only a single backslash should occur.
In java source code, a string or character denotation, backslash is the escape character, transforming the next one into a special meaning. Backslash itself should be given doubled, as \\. The string value itself will have only one backslash character.
If you read special text, using backslash escaping (like \n for a line break), then use the non-regex replace of strings:
// First escapes of other:
path = path.replace("\\n", "\n"); // Text `\n` -> linefeed
path = path.replace("\\t", "\t"); // Text `\t` -> tab
// Then escape of backslash:
path = path.replace("\\\\", "\\"); // Text `\\` -> backslash
For file paths only the last might make sense, but it should not have been needed.

Related

How to get File Path with double-backslashes in Java

I have a program where I save school grades in a .txt File.
I want to let the user choose where this File should be saved.
It works with the JFileChooser find but Java have a problem with the
FilePath.
The filepath from the JFileChooser looks like this:
C:\Users...\Documents\n.txt
But if I want to read the TextFile in the Program Java says that
it couldn't find the Filepath.
It should look like this:
C:\Users\...\Documents\n.txt
How can I get the Path with double-backslashes?
public void actionPerformed(ActionEvent e) {
JFileChooser jf = new JFileChooser();
jf.showSaveDialog(null);
String fPath = jf.getSelectedFile().getPath();
fPath.replaceAll('\', '\\');
System.out.println(p);
}
that does not work it says invalid character constant
There are some places where the backslash serves as escape character, and must be escaped, to be simply the backslash of a Windows path separator.
These places are inside .properties files, java String literals and some more.
You could for Windows paths alternatively use a slash (POSIX compliance of Windows).
fPath = fPath.replace('\\', '/');
Backslash:
fPath = fPath.replace("\\", "\\\\");
The explanation is that a single backslash inside char and string literals must be escaped: two backslashes represent a single backslash.
With regular expressions (replaceAll) a backlash is used as command: a digit is expressed as \d and as java String: "\\d". Hence the backslash itself becomes (behold):
fPath = fPath.replaceAll("\\\\", "\\\\\\\\"); // PLEASE NOT
I almost did not see it, but methods on String do not alter it, but return a new value, so one needs to assign the result.
When using hard coded file names in Java you should always use forward slashes / as file separators. Java knows how to handle them on Windows.
Also you should not use absolute paths. You don't know if that paths will exist at the target system. You should use either relative paths starting with your classpath as root "/..." or get some system dependen places from System.getProperty() https://docs.oracle.com/javase/8/docs/api/java/lang/System.html#getProperties--
Multiple issues in your code:
public void actionPerformed(ActionEvent e) {
JFileChooser jf = new JFileChooser();
jf.showSaveDialog(null);
String fPath = jf.getSelectedFile().getPath();
// fPath is a proper file path. This can be used directly with
// new File(fPath). The contents will contain single \ character
// as Path separator
fPath.replaceAll('\', '\\');
// I guess you are trying to replace a single \ character with \\
// character. You need to escape the \ character. You need to
// consider that both parameters are regexes.
// doing it is:
// fPath.replaceAll("\\\\", "\\\\\\\\");
// And then you need to capture the return value. Strings are
// immutable in java. So it is:
// fPath = fPath.replaceAll("\\\\", "\\\\\\\\");
System.out.println(p);
// I don't know what p is. I guess you want to use fPath
}
That said, I do not understand why you want to convert the path returned by JFileChooser.
You don't need the file path with double backslashes in Java. Double backslashes are for:
The Java compiler, inside string literals.
The Java regex compiler.
Everywhere else you can obtain backslashes, or use forward slashes.
Possibly you are looking for java.util.Properties?

java.util.regex.PatternSyntaxException - when using split("\\");

I'm solving this problem in my own way. I'm trying to split the file path into Drive, folders, and file name, all into an array.
Complete class. (Github)
The problem:
String regex = "\\";
String [] divisions = path.split (regex);
This gives me an java.util.regex.PatternSyntaxException. I looked up the wiki and found [\b]
String regex = "[\b]";
String [] divisions = path.split (regex);
This doesn't work. It doesn't throw an exception, nor does it split my file path based on backspace.
Input:
► Enter path --
C:\User\Admin\NekedGaben.jpg
Output:
→ Path = C:\User\Admin\NekedGaben.jpg
→ File name = C:\User\Admin\NekedGaben
→ Extension = .jpg
My questions:
Why does "\\" throw an exception, while "[\b]" doesn't?
Why doesn't the split() split the Path string?
You should use double escaping in Java regex, i.e.:
String regex = "\\\\";
Or use static Pattern.quote(String) method:
String regex = Pattern.quote("\\");
Because \b is a single character, the compiler knows it, they're friends.
However backslash (\) is represented by \\ in Java, and \ is invalid regex, in order to escape it, you should use:
\\\\
↓ ↓
escaping
Solution:
Escape it as shown above
Don't escape, let Pattern#quote handle this for you

Java regex for Windows file path

I'm trying to build a Java regex to search a .txt file for a Windows formatted file path, however, due to the file path containing literal backslashes, my regex is failing.
The .txt file contains the line:
C\Windows\SysWOW64\ntdll.dll
However, some of the filenames in the text file are formatted like this:
C\Windows\SysWOW64\ntdll.dll (some developer stuff here...)
So I'm unable to use String.equals
To match this line, I'm using the regex:
filename = "C\\Windows\\SysWOW64\\ntdll.dll"
read = BufferedReader.readLine();
if (Pattern.compile(Pattern.quote(filename), Pattern.CASE_INSENSITIVE).matcher(read).find()) {
I've tried escaping the literal backslashes, using the replace method, i.e:
filename.replace("\\", "\\\\");
However, this is failing to find, I'm guessing this is because I need to further escape the backslashes after the Pattern has been built, I'm thinking I might need to escape upto an additional four backslashes, i.e:
Pattern.replaceAll("\\\\", "\\\\\\\\");
However, each time I try, the pattern doesn't get matched. I'm certain it's a problem with the backslashes, but I'm not sure where to do the replacement, or if there's a better way of building the pattern.
I think the problem is further being compounded as the replaceAll method also uses a regex, with means the pattern will have it's own backslashes in there, to deal with the case insensitivity.
Any input or advice would be appreciated.
Thanks
Seems like you're attempting to to a direct comparison of String against another. For exact matches, you could do (
if (read.equalsIgnoreCase(filename)) {
of simply
if (read.startsWith(filename)) {
Try this :
While reading each line from the file, replace '\' by '\\'.
Then :
String lLine = "C\\Windows\\SysWOW64\\ntdll.dll";
Pattern lPattern = Pattern.compile("C\\\\Windows\\\\SysWOW64\\\\ntdll\\.dll");
Matcher lMatcher = lPattern.matcher(lLine);
if(lMatcher.find()) {
System.out.println(lMatcher.group());
}
lLine = "C\\Windows\\SysWOW64\\ntdll.dll (some developer stuff here...)";
lMatcher = lPattern.matcher(lLine);
if(lMatcher.find()) {
System.out.println(lMatcher.group());
}
The correct usage will be:
String filename = "C\\Windows\\SysWOW64\\ntdll.dll";
String file = filename.replace('\\', ' ');

Splitting filenames using system file separator symbol

I have a complete file path and I want to get the file name.
I am using the following instruction:
String[] splittedFileName = fileName.split(System.getProperty("file.separator"));
String simpleFileName = splittedFileName[splittedFileName.length-1];
But on Windows it gives:
java.util.regex.PatternSyntaxException: Unexpected internal error near index 1
\
^
Can I avoid this exception? Is there a better way to do this?
The problem is that \ has to be escaped in order to use it as backslash within a regular expression. You should either use a splitting API which doesn't use regular expressions, or use Pattern.quote first:
// Alternative: use Pattern.quote(File.separator)
String pattern = Pattern.quote(System.getProperty("file.separator"));
String[] splittedFileName = fileName.split(pattern);
Or even better, use the File API for this:
File file = new File(fileName);
String simpleFileName = file.getName();
When you write a file name, you should use System.getProperty("file.separator").
When you read a file name, you could possibly have either the forward slash or the backward slash as a file separator.
You might want to try the following:
fileName = fileName.replace("\\", "/");
String[] splittedFileName = fileName.split("/"));
String simpleFileName = splittedFileName[splittedFileName.length-1];
First of all, for this specific problem I'd recommend using the java.util.File class instead of a regex.
That being said, the root of the problem you're running into is that the backslash character '\' signifies an escape sequence in Java regular expressions. What's happening is the regex parser is seeing the backslash and expecting there to be another character after it which would complete the escape sequence. The easiest way to get around this is to use the java.util.regex.Pattern.quote() method which will escape any special characters in the string you give it.
With this change your code becomes:
String splitRegex = Pattern.quote(System.getProperty("file.separator"));
String[] splittedFileName = fileName.split(splitRegex);
String simpleFileName = splittedFileName[splittedFileName.length-1];
Another simpler way could be to do
File f = new File(path);
String fileName = f.getName();
I believe this will work provided the paths are compatible with the platform, i.e. not sure if path "c:\file.txt" will work on Linux or not.

Java Regex - Changing path with an alias

I have a path called $SERVER/public_html/ab1/ab2/.
I want to change it so that instead of $SERVER it just replaces it with my user directory. So I do
path = path.replaceFirst("\\$SERVER", System.getProperty("user.dir"));
but when I run it, it removes my \ in the new string.
F:Programming ProjectsJava Project/public_html/ab1/ab2/
Pattern has a String quote(String) function that will help you for the first string and Matcher has String quoteReplacement(String) for the second:
path = path.replaceFirst(java.util.regex.Pattern.quote("$SERVER"), java.util.regex.Matcher.quoteReplacement(System.getProperty("user.dir")));
edit: the reason you have to escape anything is because the second string has the semantics of Matcher.appendReplacement which treats backslashes and dollars as escape next char and insert captured group resp.
from the doc:
Note that backslashes () and dollar
signs ($) in the replacement string
may cause the results to be different
than if it were being treated as a
literal replacement string. Dollar
signs may be treated as references to
captured subsequences as described
above, and backslashes are used to
escape literal characters in the
replacement string.
a more obvious solution is (be careful of the needed escaped with that backslash)
path = path.replaceFirst("\\$SERVER", System.getProperty("user.dir").replaceAll("\\\\","\\\\\\\\"));
Yea you are completly right. I am trying to figure out why it is happening so.
But at the moment the only think I can suggest is to go with such a solution.
public class RegExTest
{
public static void main(String[] args)
{
String path = "$SERVER/public_html/ab1/ab2";
System.out.println("path before="+path);
String user = System.getProperty("user.dir");
System.out.println("user="+user);
System.out.println("replaceFirst using user="+path.replaceFirst("\\$SERVER", user));
path = path.replaceFirst("\\$SERVER", "");
path = user +path;
System.out.println("path after="+path);
}
}
EDIT: ..Why it does that?
From what I see in the code of the method line 701 to 708 they must do it. They just skip them. As to the reason why they do it, I still am not sure.
EDIT2:
OK reading the doc for the method answers it all. They do it so they can interpret accordingly special characters. Thus when reading the replacement they spot a slash the algorithm assumes it can be a part of special character and in result skips it.
if (nextChar == '\\') {
cursor++;
nextChar = replacement.charAt(cursor);
result.append(nextChar);
cursor++;
} else if (nextChar == '$') {
// Skip past $
cursor++;
Ok so in Windows the default slashes look like so '\' whereas on *nix the slashes look like so '/' . The simplest way to get through this problem is to invoke the replace function with the following parameters '\\' and '/' . That way you path will have its slashes all facing the same way.

Categories

Resources