мне действительно нужно 4 строки кода, чтобы получить значение из середины строки? - PullRequest
2 голосов
/ 01 сентября 2011

Мне нужно получить значение из пути к файлу.предположим, что мой путь похож на любой другой путь:

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

Я могу вывести имя 'A_Specific_Folder' во время выполнения, и мне нужно получить 'what_i_want'.Я знаю, что what_i_want - это число

. В настоящее время я использую регулярное выражение, подобное этому:

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;
}

Все это только для того, чтобы получить это tinyValue из одной строки.Теперь предположим, что я должен иметь это в методе, потому что я использую его в 10 местах.Но в одном из мест мне внезапно нужно сделать какую-то другую операцию с перемешиванием, которая снова потребовала бы от меня выполнения всей работы по скороговорке и сопоставлению с одним и тем же регулярным выражением, просто чтобы получить matcher.end (1), потому что, возможно, это всеМне нужно там.

Есть ли более короткий способ сделать это?

спасибо.

Ответы [ 7 ]

5 голосов
/ 01 сентября 2011

Я бы использовал File API и проверил бы родительское имя:

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;
}

Или рекурсивный эквивалент:

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);
}
2 голосов
/ 01 сентября 2011

С Apache Commons Lang вы можете пойти с этим:

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

Удобный для чтения One-Liner, кросс-платформенный совместимый.

Вы можете рассмотретьиспользуя FilenameUtils.normalize(path, true) вместо FilenameUtils.separatorsToUnix(path), если вы хотите избавиться от двойных и одноточечных шагов пути.

2 голосов
/ 01 сентября 2011

Я вижу несколько незначительных проблем в вашем коде:

  • Если varContainingNameOfSpecificFolder содержит символы, которые имеют значение в регулярных выражениях (. является наиболее вероятным кандидатом), то вы необходимо использовать Pattern.quote() для цитирования этой части.
  • использование String.format() не нужно, вы можете просто использовать String конкатенацию, используя +, что проще для чтения.
  • вам не нужно присваивать myValue, просто return результат substring
  • вызов substring ненужен здесь!Простая замена этого выражения на matcher.group(1) имеет тот же эффект!
  • с использованием String.replaceAll() может быть допустимым сочетанием клавиш, но вам придется изменить свое регулярное выражениенемного.

Так что моя версия будет выглядеть так:

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;
}

Если вам не нужна проверка ошибок (так как ваш код этого тоже не делает), вы можете просто вернуть результат метода replaceAll() и использовать метод из двух строк:

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

Однако я настоятельно рекомендую вам сохранить его, иначе выможет легко пропустить неприятные ошибки в вашем коде.

1 голос
/ 01 сентября 2011

Двухслойная (просто чтобы доказать, что это возможно):

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

Обратите внимание, что только работает с правильным вводом. пути, которые не содержат имя папки или не имеют номера в нужном месте, вызовут различные исключения во время выполнения. Надежный код требует гораздо больше строк кода ...

0 голосов
/ 01 сентября 2011

Я бы постарался избежать дорогостоящих регулярных выражений:

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 ) ); 
}
0 голосов
/ 01 сентября 2011

Есть ли более короткий способ сделать это?

Конечно;тривиально просто элитировать временных.Кроме того, не скрывайте свои зависимости.Да, и Matcher уже предоставляет интерфейс для «дайте мне ту часть, которая соответствует всему шаблону», поэтому нам не нужно искать его в исходной строке.

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 голосов
/ 01 сентября 2011

Предполагая, что подстрока всегда 4-ая, это может соответствовать вашим потребностям:

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

РЕДАКТИРОВАНИЕ, чтобы показать, что это возможно только в одной строке.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...