Làm thế nào để trích xuất các số từ một chuỗi và nhận một mảng int?


109

Tôi có một biến Chuỗi (về cơ bản là một câu tiếng Anh với số lượng không xác định) và tôi muốn trích xuất tất cả các số thành một mảng số nguyên. Tôi đã tự hỏi liệu có một giải pháp nhanh chóng với biểu thức chính quy không?


Tôi đã sử dụng giải pháp của Sean và thay đổi nó một chút:

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

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

1
Các số có được bao quanh bởi dấu cách hoặc các ký tự khác không? Các số được định dạng như thế nào, chúng có phải là hệ thập lục phân, bát phân, nhị phân, thập phân không?
Buhake Sindi

Tôi nghĩ nó đã rõ ràng từ câu hỏi: đó là một câu tiếng Anh với các con số. Hơn nữa, tôi đang nói về một mảng số nguyên, vì vậy những gì tôi đang tìm kiếm là số nguyên.
John Manak

Câu trả lời:


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

... bản in -212.


-? khớp với một dấu phủ định ở đầu - tùy chọn. \ d khớp với một chữ số và chúng ta cần viết \như \\trong Chuỗi Java. Vì vậy, \ d + khớp với 1 hoặc nhiều chữ số.


4
Bạn có thể bổ sung câu trả lời của mình bằng cách giải thích cụm từ thông dụng của bạn được không?
OscarRyz

3
-? khớp với một dấu phủ định ở đầu - tùy chọn. \ d khớp với một chữ số và chúng ta cần viết \ as \\ trong một Chuỗi Java. Vì vậy, \\ d + khớp với 1 chữ số khác
Sean Owen

7
Tôi đã thay đổi biểu thức của mình thành Pattern.compile ("-? [\\ d \\.] +") Để hỗ trợ float. Bạn chắc chắn dẫn tôi trên con đường, Thx!
jlengrand

Phương pháp này phát hiện các chữ số nhưng không phát hiện các số đã định dạng, ví dụ 2,000. Đối với việc sử dụng đó-?\\d+,?\\d+|-?\\d+
Mugoma J. Okomba

Điều đó chỉ hỗ trợ một dấu phẩy duy nhất, vì vậy sẽ thiếu "2.000.000". Nó cũng chấp nhận các chuỗi như "2,00". Nếu dấu phân cách bằng dấu phẩy phải được hỗ trợ, thì: -?\\d+(,\\d{3})*sẽ hoạt động.
Sean Owen

52

Điều gì về sử dụng replaceAllphương thức java.lang.String:

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

Đầu ra:

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

Sự miêu tả

[^-?0-9]+
  • []phân tách một tập hợp các ký tự để được đối sánh đơn lẻ, tức là chỉ một lần theo bất kỳ thứ tự nào
  • ^Mã định danh đặc biệt được sử dụng ở đầu tập hợp, được sử dụng để chỉ ra khớp với tất cả các ký tự không có trong tập hợp được phân tách, thay vì tất cả các ký tự có trong tập hợp.
  • + Từ một lần đến không giới hạn, nhiều lần nhất có thể, trả lại khi cần
  • -? Một trong các ký tự “-” và “?”
  • 0-9 Một ký tự trong phạm vi từ “0” đến “9”

4
Tại sao bạn muốn giữ dấu chấm hỏi? Ngoài ra, xử lý này -bởi chính nó như là một con số, cùng với những điều thích 9-, ---61-2-3.
Alan Moore

1
Một giải pháp thay thế rất hay mà không cần sử dụng thư viện nhập;)
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

Bạn thực sự có thể thay thế [0-9] bằng \ d, nhưng điều đó liên quan đến việc thoát dấu gạch chéo ngược kép, điều này khiến nó khó đọc hơn.


Rất tiếc. Sean's xử lý số âm, vì vậy đó là một cải tiến.
lề

2
bạn sẽ xử lý số âm quá nếu bạn sử dụng "-? [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();

Điều này là để trích xuất các số giữ lại phần thập phân


Không xử lý âm
OneCricketeer

5

Câu trả lời được chấp nhận phát hiện các chữ số nhưng không phát hiện các số đã định dạng, ví dụ 2.000, cũng không phải số thập phân, ví dụ 4.8. Để sử dụng như vậy -?\\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);

Đầu ra: [4.8, 2,000]


1
@JulienS: Tôi không đồng ý. Regex này làm được nhiều hơn những gì OP yêu cầu, và nó làm không chính xác. (Ít nhất, phần thập phân nên ở trong một nhóm tùy chọn, với mọi thứ trong đó là bắt buộc và tham lam:. (?:\.\d+)?)
Alan Moore

Bạn chắc chắn có một điểm ở đó cho phần thập phân. Tuy nhiên, nó rất phổ biến để gặp phải các số được định dạng.
Julien

@AlanMoore nhiều khách truy cập SO đang tìm kiếm bất kỳ / cách nào khác nhau để giải quyết các vấn đề có sự giống / khác nhau khác nhau và đề xuất được đưa ra sẽ rất hữu ích. Ngay cả OP có thể đã đơn giản hóa quá mức.
Mugoma J. Okomba,

4

đối với số hữu tỉ, hãy sử dụng cái này: (([0-9]+.[0-9]*)|([0-9]*.[0-9]+)|([0-9]+))


1
OP cho biết số nguyên, không phải số thực. Ngoài ra, bạn đã quên thoát khỏi dấu chấm và không cần dấu ngoặc đơn nào trong số đó.
Alan Moore

3

Sử dụng Java 8, bạn có thể làm:

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]

Nếu bạn không có số âm, bạn có thể loại bỏ replaceAll(và sử dụng !s.isEmpty()trong filter), vì điều đó chỉ để phân chia đúng một cái gì đó như 2-34(điều này cũng có thể được xử lý hoàn toàn bằng regex in split, nhưng nó khá phức tạp).

Arrays.streambiến của chúng tôi String[]thành một Stream<String>.

filterloại bỏ các chuỗi trống ở đầu và cuối cũng như bất kỳ chuỗi nào -không phải là một phần của số.

mapToInt(Integer::parseInt).toArray()kêu gọi parseIntmỗi người Stringcung cấp cho chúng tôi một int[].


Ngoài ra, Java 9 có phương thức Matcher.results , phương thức này sẽ cho phép một số thứ như:

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]

Như hiện tại, cả hai đều không phải là một cải tiến lớn so với việc chỉ lặp lại các kết quả với Pattern/ Matchernhư được hiển thị trong các câu trả lời khác, nhưng sẽ đơn giản hơn nếu bạn muốn theo dõi điều này với các hoạt động phức tạp hơn được đơn giản hóa đáng kể với việc sử dụng dòng suối.


1

Trích xuất tất cả các số thực bằng cách sử dụng này.

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

Các ký tự phân số và nhóm để biểu diễn số thực có thể khác nhau giữa các ngôn ngữ. Cùng một số thực có thể được viết theo những cách rất khác nhau tùy thuộc vào ngôn ngữ.

Con số hai triệu trong tiếng Đức

2.000.000,00

và bằng tiếng Anh

2.000.000,00

Một phương pháp để trích xuất đầy đủ các số thực từ một chuỗi đã cho theo một ngôn ngữ không thể hiểu được:

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

Nếu bạn muốn loại trừ các số có trong các từ, chẳng hạn như bar1 hoặc aa1bb, thì hãy thêm ranh giới từ \ b vào bất kỳ câu trả lời dựa trên regex nào. Ví dụ:

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

hiển thị:

2
12

1

Tôi khuyên bạn nên kiểm tra các giá trị ASCII để trích xuất các số từ một Chuỗi Giả sử bạn có một Chuỗi đầu vào là myname12345 và nếu bạn muốn chỉ trích xuất các số 12345, bạn có thể làm như vậy bằng cách chuyển đổi Chuỗi thành Mảng ký tự trước tiên, sau đó sử dụng mã giả sau

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

sau khi các số được trích xuất, nối chúng vào một mảng

Hi vọng điêu nay co ich


Chuỗi Java được tính là chuỗi đơn vị mã Unicode / UTF-16. Theo thiết kế của UTF-16, 128 ký tự đầu tiên có cùng giá trị (không cùng kích thước) với bảng mã ASCII của chúng; Ngoài ra, việc nghĩ rằng bạn đang xử lý ASCII sẽ dẫn đến sai sót.
Tom Blodget

0

Tôi thấy biểu thức này đơn giản nhất

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

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

chỉ trích xuất các số từ chuỗi

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.