Как извлечь числа из строки и получить массив целых чисел?

109

У меня есть строковая переменная (в основном английское предложение с неопределенным количеством чисел), и я хотел бы извлечь все числа в массив целых чисел. Мне было интересно, есть ли быстрое решение с регулярными выражениями?


Я использовал решение Шона и немного изменил его:

LinkedList<String> numbers = new LinkedList<String>();

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(line); 
while (m.find()) {
   numbers.add(m.group());
}
Джон Манак
источник
1
Окружены ли числа пробелами или другими символами? Как форматируются числа: шестнадцатеричные, восьмеричные, двоичные, десятичные?
Buhake Sindi 02
Я подумал, что это понятно из вопроса: это английское предложение с числами. Более того, я говорил о целочисленном массиве, поэтому искал целые числа.
Джон Манак

Ответы:

175
Pattern p = Pattern.compile("-?\\d+");
Matcher m = p.matcher("There are more than -2 and less than 12 numbers here");
while (m.find()) {
  System.out.println(m.group());
}

... печатает -2и 12.


-? соответствует ведущему отрицательному знаку - необязательно. \ d соответствует цифре, и нам нужно писать \как \\в строке Java. Итак, \ d + соответствует 1 или более цифрам.

Шон Оуэн
источник
4
Не могли бы вы дополнить свой ответ, объяснив свое регулярное выражение?
OscarRyz 02
3
-? соответствует ведущему отрицательному знаку - необязательно. \ d соответствует цифре, и нам нужно писать \ как \\ в строке Java. Итак, \\ d + соответствует еще 1 цифре
Шон Оуэн
7
Я изменил свое выражение на Pattern.compile ("-? [\\ d \\.] +"), Чтобы поддерживать числа с плавающей запятой. Вы определенно ведете меня по пути, спасибо!
jlengrand
Этот метод обнаруживает цифры, но не определяет форматированные числа, например 2,000. За такое использование-?\\d+,?\\d+|-?\\d+
Мугома Дж. Окомба 09
Это поддерживает только одну запятую, поэтому будет пропущено «2,000,000». Он также принимает такие строки, как «2,00». Если необходимо поддерживать разделители запятых, то: -?\\d+(,\\d{3})*должно работать.
Шон Оуэн,
52

Как насчет использования replaceAllметода java.lang.String:

    String str = "qwerty-1qwerty-2 455 f0gfg 4";      
    str = str.replaceAll("[^-?0-9]+", " "); 
    System.out.println(Arrays.asList(str.trim().split(" ")));

Вывод:

[-1, -2, 455, 0, 4]

Описание

[^-?0-9]+
  • [и ]ограничивает набор символов, которые должны быть сопоставлены по одному, то есть только один раз в любом порядке
  • ^Специальный идентификатор, используемый в начале набора, используется для указания соответствия всем символам, отсутствующим в наборе с разделителями, вместо всех символов, присутствующих в наборе.
  • + От одного до неограниченного количества раз, столько раз, сколько возможно, возвращая по мере необходимости
  • -? Один из символов «-» и «?»
  • 0-9 Символ в диапазоне от «0» до «9».
Максим Шустин
источник
4
Почему вы хотите оставить вопросительные знаки? Кроме того , это лечит -сам по себе , как число, наряду с вещами , как 9-, ---6, и 1-2-3.
Алан Мур
1
Очень хорошая альтернатива без использования импортированных библиотек;)
Jcc.Sanabria
18
Pattern p = Pattern.compile("[0-9]+");
Matcher m = p.matcher(myString);
while (m.find()) {
    int n = Integer.parseInt(m.group());
    // append n to list
}
// convert list to array, etc

Фактически вы можете заменить [0-9] на \ d, но это требует экранирования двойной обратной косой черты, что затрудняет чтение.

звездный
источник
Упс. Шон обрабатывает отрицательные числа, так что это улучшение.
sidereal
2
ваш тоже будет обрабатывать отрицательные числа, если вы используете "-? [0-9] +"
cegprakash
9
  StringBuffer sBuffer = new StringBuffer();
  Pattern p = Pattern.compile("[0-9]+.[0-9]*|[0-9]*.[0-9]+|[0-9]+");
  Matcher m = p.matcher(str);
  while (m.find()) {
    sBuffer.append(m.group());
  }
  return sBuffer.toString();

Это для извлечения чисел, сохраняющих десятичную дробь.

Каннан
источник
Не обрабатывает негативы
OneCricketeer
5

Принятый ответ обнаруживает цифры, но не определяет ни форматированные числа, например, 2000, ни десятичные дроби, например 4.8. Для такого использования -?\\d+(,\\d+)*?\\.?\\d+?:

        Pattern p = Pattern.compile("-?\\d+(,\\d+)*?\\.?\\d+?");
        List<String> numbers = new ArrayList<String>();
        Matcher m = p.matcher("Government has distributed 4.8 million textbooks to 2,000 schools");
        while (m.find()) {  
            numbers.add(m.group());
        }   
        System.out.println(numbers);

Вывод: [4.8, 2,000]

Мугома Дж. Окомба
источник
1
@JulienS .: Я не согласен. Это регулярное выражение делает гораздо больше, чем просил OP, и делает это неправильно. (По крайней мере, дробная часть должна быть в факультативной группе, со всем в нем требуется , и жадный: (?:\.\d+)?.)
Алан Мур
У вас определенно есть точка для десятичной части. Однако очень часто встречаются форматированные числа.
Жюльен
@AlanMoore: многие посетители SO ищут любые / разные способы решения проблем с различным сходством / различием, и полезно, чтобы это предложение было поднято. Даже OP мог быть слишком упрощенным.
Mugoma J. Okomba
4

для рациональных чисел используйте это: (([0-9]+.[0-9]*)|([0-9]*.[0-9]+)|([0-9]+))

Андрей
источник
1
OP сказал целые числа, а не действительные числа. Кроме того, вы забыли убрать точки, и в скобках нет необходимости.
Алан Мур
3

Используя Java 8, вы можете:

String str = "There 0 are 1 some -2-34 -numbers 567 here 890 .";
int[] ints = Arrays.stream(str.replaceAll("-", " -").split("[^-\\d]+"))
                 .filter(s -> !s.matches("-?"))
                 .mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(ints)); // prints [0, 1, -2, -34, 567, 890]

Если у вас нет отрицательных чисел, вы можете избавиться от replaceAll(и использовать !s.isEmpty()in filter), поскольку это только для правильного разделения чего-то вроде 2-34(это также можно обработать чисто с помощью регулярного выражения split, но это довольно сложно).

Arrays.streamпревращает наш String[]в Stream<String>.

filterизбавляется от начальных и конечных пустых строк, а также от любых, -которые не являются частью числа.

mapToInt(Integer::parseInt).toArray()призывает parseIntкаждого Stringдать нам int[].


В качестве альтернативы в Java 9 есть метод Matcher.results , который должен позволять что-то вроде:

Pattern p = Pattern.compile("-?\\d+");
Matcher m = p.matcher("There 0 are 1 some -2-34 -numbers 567 here 890 .");
int[] ints = m.results().map(MatchResults::group).mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(ints)); // prints [0, 1, -2, -34, 567, 890]

В его нынешнем виде ни один из них не является большим улучшением по сравнению с простым циклом по результатам с помощью Pattern/, Matcherкак показано в других ответах, но это должно быть проще, если вы хотите продолжить это с помощью более сложных операций, которые значительно упрощаются с использованием потоки.

Бернхард Баркер
источник
1

Извлеките все действительные числа, используя это.

public static ArrayList<Double> extractNumbersInOrder(String str){

    str+='a';
    double[] returnArray = new double[]{};

    ArrayList<Double> list = new ArrayList<Double>();
    String singleNum="";
    Boolean numStarted;
    for(char c:str.toCharArray()){

        if(isNumber(c)){
            singleNum+=c;

        } else {
            if(!singleNum.equals("")){  //number ended
                list.add(Double.valueOf(singleNum));
                System.out.println(singleNum);
                singleNum="";
            }
        }
    }

    return list;
}


public static boolean isNumber(char c){
    if(Character.isDigit(c)||c=='-'||c=='+'||c=='.'){
        return true;
    } else {
        return false;
    }
}
Размах 68
источник
1

Знаки дроби и группировки для представления действительных чисел могут различаться в зависимости от языка. Одно и то же действительное число можно записать по-разному в зависимости от языка.

Число два миллиона на немецком языке

2,000,000.00

и на английском

2.000.000,00

Метод полного извлечения действительных чисел из заданной строки независимым от языка способом:

public List<BigDecimal> extractDecimals(final String s, final char fraction, final char grouping) {
    List<BigDecimal> decimals = new ArrayList<BigDecimal>();
    //Remove grouping character for easier regexp extraction
    StringBuilder noGrouping = new StringBuilder();
    int i = 0;
    while(i >= 0 && i < s.length()) {
        char c = s.charAt(i);
        if(c == grouping) {
            int prev = i-1, next = i+1;
            boolean isValidGroupingChar =
                    prev >= 0 && Character.isDigit(s.charAt(prev)) &&
                    next < s.length() && Character.isDigit(s.charAt(next));                 
            if(!isValidGroupingChar)
                noGrouping.append(c);
            i++;
        } else {
            noGrouping.append(c);
            i++;
        }
    }
    //the '.' character has to be escaped in regular expressions
    String fractionRegex = fraction == POINT ? "\\." : String.valueOf(fraction);
    Pattern p = Pattern.compile("-?(\\d+" + fractionRegex + "\\d+|\\d+)");
    Matcher m = p.matcher(noGrouping);
    while (m.find()) {
        String match = m.group().replace(COMMA, POINT);
        decimals.add(new BigDecimal(match));
    }
    return decimals;
}
И нас
источник
1

Если вы хотите исключить числа, содержащиеся в словах, например bar1 или aa1bb, добавьте границы слов \ b к любому из ответов на основе регулярных выражений. Например:

Pattern p = Pattern.compile("\\b-?\\d+\\b");
Matcher m = p.matcher("9There 9are more9 th9an -2 and less than 12 numbers here9");
while (m.find()) {
  System.out.println(m.group());
}

дисплеи:

2
12
DXL
источник
1

Я бы предложил проверить значения ASCII для извлечения чисел из строки. Предположим, у вас есть входная строка как myname12345, и если вы хотите просто извлечь числа 12345, вы можете сделать это, сначала преобразовав строку в массив символов, а затем используйте следующий псевдокод

    for(int i=0; i < CharacterArray.length; i++)
    {
        if( a[i] >=48 && a[i] <= 58)
            System.out.print(a[i]);
    }

как только числа будут извлечены, добавьте их в массив

Надеюсь это поможет

The_Fresher
источник
Строка Java - это посчитанная последовательность кодовых единиц Unicode / UTF-16. По дизайну UTF-16 первые 128 символов имеют то же значение (но не того же размера), что и их кодировка ASCII; Кроме того, мысль о том, что вы имеете дело с ASCII, приведет к ошибкам.
Том Блоджет
0

Я нашел это выражение самым простым

String[] extractednums = msg.split("\\\\D++");
user2902302
источник
-1
public static String extractNumberFromString(String number) {
    String num = number.replaceAll("[^0-9]+", " ");
    return num.replaceAll(" ", "");
}

извлекает только числа из строки

user3509903
источник