如何从字符串中提取数字并获得整数数组?

117

我有一个字符串变量(基本上是一个含有未指定数量数字的英文句子),我想把其中所有数字提取出来并存入整数数组中。我想知道是否有一种使用正则表达式的快速解决方案?


我使用了Sean的解决方案,并稍作修改:

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
我认为从问题中已经很清楚了:这是一个带有数字的英语句子。此外,我在谈论整数数组,所以我要找的是整数。 - John Manak
13个回答

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

...打印出-212


-?匹配一个可选的前导负号。 \d匹配数字,虽然在Java字符串中需要用\\表示\。因此,\d+匹配1个或多个数字。


4
你能否补充一下你的回答并解释一下你的正则表达式? - OscarRyz
3
-? 匹配一个可选的负号。 \d 匹配一个数字,在Java字符串中需要用 \ 表示。因此,\d+ 匹配1个或多个数字。 - Sean Owen
8
我将表达式更改为Pattern.compile("-?[\d\.]+")以支持浮点数。你确实指引了我正确的方向,谢谢! - jlengrand
该方法可以检测数字,但无法检测格式化的数字,例如 2,000。对于这种情况,请使用 -?\\d+,?\\d+|-?\\d+ - Mugoma J. Okomba
它只支持单个逗号,因此会忽略“2,000,000”。它还接受像“2,00”这样的字符串。如果必须支持逗号分隔符,则-?\\d+(,\\d{3})*应该可以工作。 - Sean Owen

55

那就使用 replaceAll 这个 Java 语言的 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”之间的字符

6
为什么要保留问号?此外,这个处理方式将单独的横线视为数字,以及像9-、---6和1-2-3这样的内容。 - Alan Moore
1
一个非常好的选择,而不需要使用导入库 ;) - Jcc.Sanabria

19
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

实际上,您可以用 \d 替换 [0-9],但这需要双反斜杠转义,这会使其更难读。


糟糕。Sean的处理负数,所以这是一个改进。 - sidereal
2
如果你使用“-?[0-9]+”,你的程序也可以处理负数。 - cegprakash

10
  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
我认为应该转义点 "(-?[0-9]+\\.[0-9]*|-?[0-9]*\\.[0-9]+|-?[0-9]+)",要处理负值,只需要添加 -? - Moussa

8

接受的答案可以检测数字,但无法检测格式化数字,例如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]

2
@JulienS.:我不同意。这个正则表达式做的比OP要求的多得多,而且它还有错误。(至少,小数部分应该在一个可选组中,其中包括所有内容都是必需和贪婪的:(?:\.\d+)?。) - Alan Moore
对于小数部分,你确实有一定的观点。然而,遇到格式化数字是非常普遍的。 - Julien
@AlanMoore,许多访问SO的人都在寻找不同的方式来解决各种相似/不同的问题,有建议会很有帮助。即使是OP可能也过于简化了问题。 - Mugoma J. Okomba

5
使用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(并在 filter 中使用 !s.isEmpty()),因为这仅适用于正确拆分像 2-34 这样的内容(这也可以纯粹使用正则表达式在 split 中处理,但它非常复杂)。 Arrays.stream 将我们的 String[] 转换为 Stream<String>filter 摆脱了前导和尾随空字符串以及任何不是数字一部分的 -mapToInt(Integer::parseInt).toArray() 在每个 String 上调用 parseInt,以便给我们一个 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在结果上循环更好,但如果你想要进行更复杂的操作,使用流将显著简化这些操作。请注意,保留原文中的html标签

4

对于有理数,请使用以下正则表达式:(([0-9]+.[0-9]*)|([0-9]*.[0-9]+)|([0-9]+))


1
OP说的是整数,不是实数。另外,你忘记转义点了,这些括号都是不必要的。 - Alan Moore

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
使用此代码提取所有实数。
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
如果你想排除包含在单词中的数字,例如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());
}

displays:

2
12

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接