Як витягнути числа з рядка та отримати масив ints?


109

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


Я використав розчин Шона і трохи змінив його:

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

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

1
Чи цифри оточені пробілами чи іншими символами? Як форматуються числа, вони шістнадцяткові, восьмеричні, двійкові, десяткові?
Бухаке Сінді

Я подумав, що це зрозуміло з питання: це англійське речення з цифрами. Більше того, я говорив про цілий масив, тому я шукав цілі числа.
Джон Манак

Відповіді:


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 String. Отже, \ d + відповідає 1 або більше цифр.


4
Чи можете ви доповнити свою відповідь, пояснивши, будь ласка, свій регулярний вираз?
OscarRyz

3
-? відповідає провідному негативному знаку - необов'язково. \ d відповідає цифрі, і нам потрібно записати \ як \\ у рядок Java. Отже, \\ d + відповідає ще
одній цифрі

7
Я змінив своє вираження на Pattern.compile ("-? [\\ d \\.] +") Для підтримки floats. Ви напевно ведете мене в дорогу, Thx!
jlengrand

Цей метод виявляє цифри, але не виявляє форматовані числа, наприклад 2,000. Для такого використання-?\\d+,?\\d+|-?\\d+
Mugoma J. Okomba

Це підтримує лише одну кому, так що буде пропущено "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, але це передбачає подвійний зворотний нахил, який ускладнює читання.


Уопс. Шон обробляє негативні цифри, тож це покращення.
сидереал

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

Прийнята відповідь виявляє цифри, але не виявляє форматованих чисел, наприклад, 2 000, ні десяткових знаків, наприклад 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. Я не згоден. Цей регулярний вираз робить набагато більше, ніж просив ОП, і робить це неправильно. (Принаймні, десяткова частина повинна бути в необов'язковій групі, з усім необхідним і жадібним:. (?:\.\d+)?)
Алан Мур

У вас, безумовно, є точка для десяткової частини. Однак дуже часто зустрічаються відформатовані номери.
Жульєн

@AlanMoore багато відвідувачів SO шукають будь-які / різні способи вирішення проблем із різною схожістю / різницею, і корисно, щоб пропозиція була піднята. Навіть ОП може бути надто спрощеним.
Mugoma J. Okomba

4

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


1
В ОП сказали цілі числа, а не дійсні числа. Крім того, ви забули уникати крапок, і жодна з цих дужок не потрібна.
Алан Мур

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()в 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;
    }
}

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

1

Я б запропонував перевірити значення ASCII для вилучення чисел з String Припустимо, у вас є рядок введення як myname12345, і якщо ви хочете просто витягнути числа 12345, ви можете це зробити, спершу перетворивши String в масив символів, а потім скористайтеся наступним псевдокодом

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

як тільки числа витягнуті, додайте їх до масиву

Сподіваюся, це допомагає


Рядок Java вважається послідовністю кодових одиниць Unicode / UTF-16. За конструкцією UTF-16 перші 128 символів мають те саме значення (не того самого розміру), що їх кодування ASCII; Крім того, думка, що ви маєте справу з ASCII, призведе до помилок.
Том Блоджет

0

Я вважав цей вираз найпростішим

String[] extractednums = msg.split("\\\\D++");

-1
public static String extractNumberFromString(String number) {
    String num = number.replaceAll("[^0-9]+", " ");
    return num.replaceAll(" ", "");
}

витягує лише рядки з рядка

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.