Извлечение двух чисел из строки - PullRequest
3 голосов
/ 11 ноября 2009

У меня есть строка, подобная следующей:

"некоторое значение равно 25, но не должно быть больше 12"

Я хочу извлечь два числа из строки.

Числа являются целыми числами.

Возможно, нет текста до первого числа и текста после второго номера.

Я пытался сделать это с регулярным выражением и группами, но с треском провалился:

public MessageParser(String message) {
    Pattern stringWith2Numbers = Pattern.compile(".*(\\d?).*(\\d?).*");
    Matcher matcher = stringWith2Numbers.matcher(message);
    if (!matcher.matches()) {
        couldParse = false;
        firstNumber = 0;
        secondNumber = 0;
    } else {
        final String firstNumberString = matcher.group(1);
        firstNumber = Integer.valueOf(firstNumberString);
        final String secondNumberString = matcher.group(2);
        secondNumber = Integer.valueOf(secondNumberString);

        couldParse = true;
    }
}

Любая помощь приветствуется.

Ответы [ 3 ]

8 голосов
/ 11 ноября 2009

Ваш шаблон должен выглядеть так:

Pattern stringWith2Numbers = Pattern.compile("\\D*(\\d+)\\D+(\\d+)\\D*");

Вам необходимо принять \\d+, потому что это может быть одна или несколько цифр.

3 голосов
/ 11 ноября 2009

Ваши ".*" шаблоны являются жадными, как и их привычка, и поглощают столько, сколько могут - что будет всей цепочкой. Так что первый ".*" соответствует всей строке, оставляя спорный спор. Кроме того, в ваших "\\d?" предложениях указывается одна цифра, которая является необязательной, ни одна из которых не является той, которую вы хотите.

Это, вероятно, больше соответствует тому, за что вы стреляете:

Pattern stringWith2Numbers = Pattern.compile(".*?(\\d+).*?(\\d+).*?");

Конечно, раз уж вы не заботитесь о вещах до или после чисел, зачем их беспокоить?

Pattern stringWith2Numbers = Pattern.compile("(\\d+).*?(\\d+)");

Это должно сработать.

Редактировать: Не торопясь с написанием потрясающе классных комиксов, Алан Мур указал на некоторые проблемы с моим решением в комментариях. Для начала, если у вас есть только одно многозначное число в строке, мое решение ошибочно. Применение его к «This 123 is bad string» приведет к тому, что он вернет «12» и «3», когда он должен просто потерпеть неудачу. Лучшее регулярное выражение будет предусматривать, что ДОЛЖЕН быть хотя бы один нецифровый символ, разделяющий два числа, например так:

Pattern stringWith2Numbers = Pattern.compile("(\\d+)\\D+(\\d+)");

Кроме того, matches() применяет шаблон ко всей строке , заключая его в скобки в ^ и $; find() сделает трюк, но это не то, что использовал ОП. Так что придерживаясь matches(), нам нужно вернуть эти «бесполезные» предложения перед двумя числами и после них. (Хотя лучше явно указывать их без цифр, а не с подстановочными знаками.) Так это будет выглядеть так:

Pattern stringWith2Numbers = Pattern.compile("\\D*(\\d+)\\D+(\\d+)\\D*");

... что, надо заметить, чертовски близко к ответу jjnguy.

2 голосов
/ 11 ноября 2009

Ваше регулярное выражение совпадает, но все становится первым вашим .*, а остальное совпадает с пустой строкой.

Измените свое регулярное выражение на "\\D*(\\d+)\\D+(\\d+)\\D*".

Это должно читаться как: хотя бы одна цифра, за которой следует хотя бы один символ, который не является цифрой, а затем хотя бы одна цифра.

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