开发者

do i really need 4 lines of code to get a value from the middle of a string?

I need to get a value from a file path. assume my path looks like any other path:

c:\SomeFolder\SomeOtherfolder\A_Specific_Folder\what_i_want\another_folder\bla.txt

I can infer the name of 'A_Specific_Folder' at runtime, and i need to get 'what_i_want'. I know that 'what_i_want' is a number

I currenly use a regex like this:

public String getValueThatIneed(String path) {
    String regex = String.format("%s\\\\([0-9]+)\\\\", varContainingNameOfSpecificFolder); 
    Pattern p = Pattern.compile(regex);
    Matcher matcher = compile.matcher(path);
    matcher.find(); \\because otherwise i can't use matcher.start()
    String myValue = path.substring(matcher.start(1), matcher.end(1));
    return myValue;
}

All this just to get this tinyValue from one String. Now a开发者_开发知识库ssume that i must have this in a method because I use it in 10 places. But in one of the places I suddenly need to do some other operation on the stirng that would again require me to do all the patter, matcher stuff, with the same regex, just to get matcher.end(1), because maybe thats all i need over there.

Is there shorter way to do this?

thanks.


I'd use the File API and check the parent name:

public String find(File file, String folder) {
    while (file.getParentFile() != null) {
        if(file.getParentFile().getName().equals(folder)) return file.getName();
        file = file.getParentFile();
    }
    return null;
}

Or the recursive equivalent:

public static String find(File file, String folder) {
    if(file.getParentFile() == null) return null;
    if(file.getParentFile().getName().equals(folder)) return file.getName();
    return find(file.getParentFile(), folder);
}


I see several minor problems in your code:

  • If varContainingNameOfSpecificFolder contains characters that have a meaning in regular expressions (. being the most likely candidate), then you must use Pattern.quote() to quote that part.
  • your use of String.format() is unnecessary, you can use simply String concatenation using + here, which is easier to read.
  • you don't need the assignment to myValue, simply return the result of substring
  • the substring call is unnecessary here! Simply replacing that expression with matcher.group(1) has the same effect!
  • using String.replaceAll() might be a valid shortcut, but you'd have to modify your regex slightly.

So my version would be:

public static String getValueThatIneed(String path) {
    String regex = ".*\\\\" + Pattern.quote(varContainingNameOfSpecificFolder) + "\\\\([0-9]+)\\\\.*";
    String result = path.replaceAll(regex, "$1");
    if (result.equals(path)) {
        throw new IllegalArgumentException("<" + path + "> does not contain the thin i need!");
    }
    return result;
}

If you don't care about error checking (as your code doesn't do it either) you can simply return the result of the replaceAll() method and have a two-line method:

public static String getValueThatIneed(String path) {
    String regex = ".*\\\\" + Pattern.quote(varContainingNameOfSpecificFolder) + "\\\\([0-9]+)\\\\.*";
    return path.replaceAll(regex, "$1");
}

However, I strongly encourage you to keep it, as otherwise you can easily miss nasty bugs in your code.


With Apache Commons Lang you can go with this:

String whatIWant = StringUtils.substringBetween(FilenameUtils.separatorsToUnix(path), specificFolder + "/", "/");

A readable One-Liner being cross-platform compatible.

You may want to consider using FilenameUtils.normalize(path, true) instead of FilenameUtils.separatorsToUnix(path) when you want to get rid of double and single dot path steps.


A two-liner (just to prove that it can be done):

private static String getNumber(String path, String folder) {
  String[] splits = path.split(String.format("\\\\folder\\\\", folder);
  return splits[1].substring(0,splits[1].indexOf('\\')));
}

Note that this only works with correct input. paths that don't contain the folder name or don't have a number at the right place will cause various runtime exceptions. Robust code needs a lot more lines of code...


Assuming the substring is always the 4th, this may fit your needs:

    public String getValueThatIneed(String path) {
        return (path.split("\\\\"))[3];
    }

EDITED to show it is possible in just a single line.


I would try to avoid costly regular expressions:

public String getValueThatIneed(String path) {
   int startIndex = path.indexOf( File.separator + varContainingNameOfSpecificFolder + File.separator ) + varContainingNameOfSpecificFolder.length() + 2;
   return ( startIndex < varContainingNameOfSpecificFolder.length() + 2 ) ? "" : path.substring( startIndex, path.indexOf( File.separator, startIndex ) ); 
}


Is there shorter way to do this?

Of course; it's trivial to just elide the temporaries. Also, don't hide your dependencies. Oh, and Matcher already provides an interface for "give me the part that was matched by the entire pattern", so we don't need to look it up in the original string.

public String getValueThatIneed(String path, String toFind) {
    Matcher matcher = Pattern.compile(String.format("%s\\\\([0-9]+)\\\\", toFind)).matcher(path);
    matcher.find();
    return matcher.group(1);
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜