Как извлечь числа из строки и получить массив целых? - PullRequest
101 голосов
/ 03 марта 2010

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


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

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

Pattern p = Pattern.compile("\\d+");
Matcher m = p.matcher(line); 
while (m.find()) {
   numbers.add(m.group());
}

Ответы [ 12 ]

163 голосов
/ 03 марта 2010
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 или более цифрам.

47 голосов
/ 04 сентября 2014

Как насчет использования 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»
18 голосов
/ 03 марта 2010
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, но это включает в себя двойную обратную косую черту, что затрудняет чтение.

9 голосов
/ 10 февраля 2012
  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();

Это для извлечения чисел с сохранением десятичного числа

5 голосов
/ 06 апреля 2016

Принятый ответ обнаруживает цифры, но не определяет форматированные числа, например, 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]

4 голосов
/ 03 марта 2010

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

3 голосов
/ 31 декабря 2017

Используя 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() в 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 голос
/ 19 апреля 2019

Если вы хотите исключить числа, содержащиеся в словах, например 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
1 голос
/ 18 октября 2018

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

Число два миллиона по-немецки

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 голос
/ 11 сентября 2018

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

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;
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...