Подтвердить что ты не робот

Убедитесь, что String соответствует формату String

В Java, как вы можете определить, соответствует ли строка строке (т.е.: song%03d.mp3)?

Другими словами, как реализовать следующую функцию?

/**
* @return true if formatted equals String.format(format, something), false otherwise.
**/
boolean matches(String formatted, String format);

Примеры:

matches("hello world!", "hello %s!"); // true
matches("song001.mp3", "song%03d.mp3"); // true
matches("potato", "song%03d.mp3"); // false

Может быть, есть способ конвертировать строку формата в регулярное выражение?

Разъяснение

Формат String - это параметр. Я не знаю этого заранее. song%03d.mp3 является просто примером. Это может быть любая другая форматная строка.

Если это помогает, я могу предположить, что в строке формата будет только один параметр.

4b9b3361

Ответ 1

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

// copied from java.util.Formatter
// %[argument_index$][flags][width][.precision][t]conversion
private static final String formatSpecifier
    = "%(\\d+\\$)?([-#+ 0,(\\<]*)?(\\d+)?(\\.\\d+)?([tT])?([a-zA-Z%])";

private static final Pattern formatToken = Pattern.compile(formatSpecifier);

public Pattern convert(final String format) {
    final StringBuilder regex = new StringBuilder();
    final Matcher matcher = formatToken.matcher(format);
    int lastIndex = 0;
    regex.append('^');
    while (matcher.find()) {
        regex.append(Pattern.quote(format.substring(lastIndex, matcher.start())));
        regex.append(convertToken(matcher.group(1), matcher.group(2), matcher.group(3), 
                                  matcher.group(4), matcher.group(5), matcher.group(6)));
        lastIndex = matcher.end();
    }
    regex.append(Pattern.quote(format.substring(lastIndex, format.length())));
    regex.append('$');
    return Pattern.compile(regex.toString());
}

Конечно, реализация convertToken будет проблемой. Начнем с того, что:

private static String convertToken(String index, String flags, String width, String precision, String temporal, String conversion) {
    if (conversion.equals("s")) {
        return "[\\w\\d]*";
    } else if (conversion.equals("d")) {
        return "[\\d]{" + width + "}";
    }
    throw new IllegalArgumentException("%" + index + flags + width + precision + temporal + conversion);
}

Ответ 3

Поскольку вы заранее не знаете формат, вам придется написать метод, который преобразует строку формата в regexp. Не тривиально, но возможно. Вот простой пример для двух тестовых таблиц, которые вы указали:

public static String getRegexpFromFormatString(String format)
{
    String toReturn = format;

    // escape some special regexp chars
    toReturn = toReturn.replaceAll("\\.", "\\\\.");
    toReturn = toReturn.replaceAll("\\!", "\\\\!");

    if (toReturn.indexOf("%") >= 0)
    {
        toReturn = toReturn.replaceAll("%s", "[\\\\w]+"); //accepts 0-9 A-Z a-z _

        while (toReturn.matches(".*%([0-9]+)[d]{1}.*"))
        {
            String digitStr = toReturn.replaceFirst(".*%([0-9]+)[d]{1}.*", "$1");
            int numDigits = Integer.parseInt(digitStr);
            toReturn = toReturn.replaceFirst("(.*)(%[0-9]+[d]{1})(.*)", "$1[0-9]{" + numDigits + "}$3");
        }
    }

    return "^" + toReturn + "$";
}

и некоторый тестовый код:

public static void main(String[] args) throws Exception
{
    String formats[] = {"hello %s!", "song%03d.mp3", "song%03d.mp3"};
    for (int i=0; i<formats.length; i++)
    {
        System.out.println("Format in [" + i + "]: " + formats[i]);
        System.out.println("Regexp out[" + i + "]: " + getRegexp(formats[i]));
    }

    String[] words = {"hello world!", "song001.mp3", "potato"};
    for (int i=0; i<formats.length; i++)
    {
        System.out.println("Word [" + i + "]: " + words[i] +
            " : matches=" + words[i].matches(getRegexpFromFormatString(formats[i])));
    }
}

Ответ 4

Существует не простой способ сделать это. Прямым способом было бы написать код, который преобразует строки формата (или их более простые подмножества) в регулярные выражения, а затем сопоставлять их с использованием стандартные классы регулярных выражений.

Лучше всего, вероятно, переосмыслить/реорганизовать свой код. Зачем вам это нужно?

Ответ 5

Вы можете использовать String.matches; хотя вам нужно будет использовать регулярное выражение, а не строку формата.

Не следует слишком сложно заменить что-то вроде% 03d эквивалентом регулярного выражения \d {3}

Пример:

"song001.mp3".matches( "song\\d {3} \\. mp3" )//True

"potato".matches( "song\\d {3} \\. mp3" )//False

Если вам действительно нужна строка формата, вам нужно создать функцию, заменяющую формат эквивалентом регулярного выражения, и избегает зарезервированных символов регулярного выражения; затем используйте функцию String.matches.

Ответ 7

Вы можете использовать класс Pattern для реализации метода, чтобы делать то, что вы хотите. Взгляните на примеры на странице Pattern Java api.