Sử dụng các biểu thức chính quy để trích xuất một giá trị trong Java


169

Tôi có một số chuỗi ở dạng thô:

[some text] [some number] [some more text]

Tôi muốn trích xuất văn bản trong [một số] bằng cách sử dụng các lớp Java Regex.

Tôi biết đại khái những biểu thức chính quy tôi muốn sử dụng (mặc dù tất cả các đề xuất đều được chào đón). Điều tôi thực sự quan tâm là các lệnh gọi Java để lấy chuỗi regex và sử dụng nó trên dữ liệu nguồn để tạo ra giá trị của [một số số].

EDIT: Tôi nên thêm rằng tôi chỉ quan tâm đến một [một số] (về cơ bản, ví dụ đầu tiên). Các chuỗi nguồn ngắn và tôi sẽ không tìm kiếm nhiều lần xuất hiện của [một số số].


11
... Và bây giờ tôi đi nghiên cứu. Hãy xem liệu SO có thể nhận được câu trả lời cho tôi hay không trước khi tôi tự mình tìm ra. :-P
Craig Walker

đây là một câu hỏi phỏng vấn tại một công ty ngân hàng / đầu tư / thương mại cho công nghệ phần mềm phải không? : P
ennth

@ennth Không, thậm chí không gần! Đó là mã sản xuất trên một trang web nhỏ ... nhiều mặt trăng trước đây.
Craig Walker

1
chết tiệt tôi cũng được hỏi những câu hỏi gần như chính xác như nhau trên một kỳ thi mã JP Morgan Chase Công nghệ phần mềm chỉ là một vài ngày trước: P
ennth

Câu trả lời:


316

Ví dụ đầy đủ:

private static final Pattern p = Pattern.compile("^([a-zA-Z]+)([0-9]+)(.*)");
public static void main(String[] args) {
    // create matcher for pattern p and given string
    Matcher m = p.matcher("Testing123Testing");

    // if an occurrence if a pattern was found in a given string...
    if (m.find()) {
        // ...then you can use group() methods.
        System.out.println(m.group(0)); // whole matched expression
        System.out.println(m.group(1)); // first expression from round brackets (Testing)
        System.out.println(m.group(2)); // second one (123)
        System.out.println(m.group(3)); // third one (Testing)
    }
}

Vì bạn đang tìm kiếm số đầu tiên, bạn có thể sử dụng biểu thức chính quy đó:

^\D+(\d+).*

m.group(1)sẽ trả lại cho bạn số đầu tiên. Lưu ý rằng các số đã ký có thể chứa dấu trừ:

^\D+(-?\d+).*

62
Đừng quên sử dụng lại đối tượng Patter. Biên dịch các patter mất thời gian rất lớn.
Rastislav Komara

14
Đã đồng ý. Thông thường tôi sẽ định nghĩa mẫu là mẫu cuối cùng tĩnh riêng PATTERN = Pattern.compile ("..."); Nhưng đó chỉ là tôi.
Allain Lalonde

6
chúng ta chỉ cần sử dụng Mẫu p = Pattern.compile ("\\ d +");
javaMan

15
Không có lời giải thích đây là một câu trả lời kém.
Martin Spamer

Bạn cũng có thể sử dụng lại Matcher. Gọi phương thức reset () của Matcher giữa mỗi lần sử dụng. Nếu bạn đang chia sẻ công cụ đối sánh qua nhiều luồng đồng thời, bạn nên đồng bộ hóa thao tác.
Marquez

41
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Regex1 {
    public static void main(String[]args) {
        Pattern p = Pattern.compile("\\d+");
        Matcher m = p.matcher("hello1234goodboy789very2345");
        while(m.find()) {
            System.out.println(m.group());
        }
    }
}

Đầu ra:

1234
789
2345

Câu hỏi đặc biệt chỉ yêu cầu sự xuất hiện đầu tiên của các con số.
NoBrainer

34

Allain về cơ bản có mã java, vì vậy bạn có thể sử dụng nó. Tuy nhiên, biểu thức của anh ta chỉ khớp nếu số của bạn chỉ đứng trước một luồng ký tự từ.

"(\\d+)"

sẽ có thể tìm thấy chuỗi chữ số đầu tiên. Bạn không cần chỉ định những gì trước nó, nếu bạn chắc chắn rằng đó sẽ là chuỗi chữ số đầu tiên. Tương tự như vậy, không có cách nào để chỉ định những gì sau nó, trừ khi bạn muốn điều đó. Nếu bạn chỉ muốn số và chắc chắn rằng đó sẽ là chuỗi đầu tiên gồm một hoặc nhiều chữ số thì đó là tất cả những gì bạn cần.

Nếu bạn mong đợi nó được bù bởi khoảng trắng, nó sẽ làm cho nó khác biệt hơn nữa để chỉ định

"\\s+(\\d+)\\s+"

có thể tốt hơn

Nếu bạn cần cả ba phần, điều này sẽ làm:

"(\\D+)(\\d+)(.*)"

EDIT Biểu thức được cung cấp bởi Allain và Jack đề nghị rằng bạn cần chỉ định một số tập hợp con không phải chữ số để thu được chữ số . Nếu bạn nói với công cụ regex mà bạn đang tìm kiếm \dthì nó sẽ bỏ qua mọi thứ trước các chữ số. Nếu biểu thức của J hoặc A phù hợp với mẫu của bạn, thì toàn bộ khớp bằng với chuỗi đầu vào . Và không có lý do để chỉ định nó. Nó có thể làm chậm một trận đấu sạch, nếu nó không hoàn toàn bị bỏ qua.


bạn có thể kiểm tra giả thuyết của Axemans bằng cách chạy thử nghiệm mẫu và kiểm tra hiệu suất của giải pháp so với A / J.
anjanb

Bạn không cần chỉ định bắt đầu và kết thúc chuỗi. Nếu không, những thứ như 124xxx123xxx sẽ được khớp ngay cả khi nó không phù hợp với cú pháp của anh ta? Hay là ^ và $ ẩn?
Allain Lalonde

Allain, của bạn cũng sẽ thất bại. Bạn và Jack đưa ra một giả định rằng các ký tự không có chữ số sẽ đứng trước các chữ số. Họ làm hoặc họ không làm. Trong trường hợp đó, không có biểu thức nào trong số này sẽ phân tích dòng này. Tôi nhắc lại rằng theo quy định , mẫu cho các chữ số là đủ.
Axeman

11

Ngoài Mẫu , lớp Chuỗi Java cũng có một số phương thức có thể hoạt động với các biểu thức thông thường, trong trường hợp của bạn, mã sẽ là:

"ab123abc".replaceFirst("\\D*(\\d*).*", "$1")

trong đó \\Dlà một ký tự không chữ số.


10

Trong Java 1.4 trở lên:

String input = "...";
Matcher matcher = Pattern.compile("[^0-9]+([0-9]+)[^0-9]+").matcher(input);
if (matcher.find()) {
    String someNumberStr = matcher.group(1);
    // if you need this to be an int:
    int someNumberInt = Integer.parseInt(someNumberStr);
}

8

Hàm này thu thập tất cả các chuỗi khớp từ chuỗi. Trong ví dụ này, nó lấy tất cả các địa chỉ email từ chuỗi.

static final String EMAIL_PATTERN = "[_A-Za-z0-9-\\+]+(\\.[_A-Za-z0-9-]+)*@"
        + "[A-Za-z0-9-]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})";

public List<String> getAllEmails(String message) {      
    List<String> result = null;
    Matcher matcher = Pattern.compile(EMAIL_PATTERN).matcher(message);

    if (matcher.find()) {
        result = new ArrayList<String>();
        result.add(matcher.group());

        while (matcher.find()) {
            result.add(matcher.group());
        }
    }

    return result;
}

Đối với message = "adf@gmail.com, <another@osiem.osiem>>>> lalala@aaa.pl"nó sẽ tạo Danh sách 3 yếu tố.


3

Hãy thử làm một cái gì đó như thế này:

Pattern p = Pattern.compile("^.+(\\d+).+");
Matcher m = p.matcher("Testing123Testing");

if (m.find()) {
    System.out.println(m.group(1));
}

3
-1. Bởi vì .+tham lam tiêu thụ nhân vật, \d+chỉ nắm bắt "3"từ "123". Ngoài ra, bên trong chuỗi ký tự, bạn cần thoát dấu gạch chéo ngược (ví dụ của bạn sẽ không biên dịch).
Bart Kiers

3

Giải pháp đơn giản

// Regexplanation:
// ^       beginning of line
// \\D+    1+ non-digit characters
// (\\d+)  1+ digit characters in a capture group
// .*      0+ any character
String regexStr = "^\\D+(\\d+).*";

// Compile the regex String into a Pattern
Pattern p = Pattern.compile(regexStr);

// Create a matcher with the input String
Matcher m = p.matcher(inputStr);

// If we find a match
if (m.find()) {
    // Get the String from the first capture group
    String someDigits = m.group(1);
    // ...do something with someDigits
}

Giải pháp trong lớp Util

public class MyUtil {
    private static Pattern pattern = Pattern.compile("^\\D+(\\d+).*");
    private static Matcher matcher = pattern.matcher("");

    // Assumptions: inputStr is a non-null String
    public static String extractFirstNumber(String inputStr){
        // Reset the matcher with a new input String
        matcher.reset(inputStr);

        // Check if there's a match
        if(matcher.find()){
            // Return the number (in the first capture group)
            return matcher.group(1);
        }else{
            // Return some default value, if there is no match
            return null;
        }
    }
}

...

// Use the util function and print out the result
String firstNum = MyUtil.extractFirstNumber("Testing4234Things");
System.out.println(firstNum);

1

Nhìn bạn có thể làm điều đó bằng StringTokenizer

String str = "as:"+123+"as:"+234+"as:"+345;
StringTokenizer st = new StringTokenizer(str,"as:");

while(st.hasMoreTokens())
{
  String k = st.nextToken();    // you will get first numeric data i.e 123
  int kk = Integer.parseInt(k);
  System.out.println("k string token in integer        " + kk);

  String k1 = st.nextToken();   //  you will get second numeric data i.e 234
  int kk1 = Integer.parseInt(k1);
  System.out.println("new string k1 token in integer   :" + kk1);

  String k2 = st.nextToken();   //  you will get third numeric data i.e 345
  int kk2 = Integer.parseInt(k2);
  System.out.println("k2 string token is in integer   : " + kk2);
}

Vì chúng tôi đang lấy các dữ liệu số này thành ba biến khác nhau, chúng tôi có thể sử dụng dữ liệu này ở bất kỳ đâu trong mã (để sử dụng thêm)


0

Làm thế nào về [^\\d]*([0-9]+[\\s]*[.,]{0,1}[\\s]*[0-9]*).*tôi nghĩ rằng nó sẽ chăm sóc các con số với một phần phân số. Tôi bao gồm các khoảng trắng và bao gồm ,phân cách có thể. Tôi đang cố gắng đưa các số ra khỏi một chuỗi bao gồm cả số float và tính đến việc người dùng có thể mắc lỗi và bao gồm các khoảng trắng trong khi gõ số.


0

Đôi khi bạn có thể sử dụng phương thức .split ("REGEXP") đơn giản có sẵn trong java.lang.String. Ví dụ:

String input = "first,second,third";

//To retrieve 'first' 
input.split(",")[0] 
//second
input.split(",")[1]
//third
input.split(",")[2]

0
Pattern p = Pattern.compile("(\\D+)(\\d+)(.*)");
Matcher m = p.matcher("this is your number:1234 thank you");
if (m.find()) {
    String someNumberStr = m.group(2);
    int someNumberInt = Integer.parseInt(someNumberStr);
}

1
Vui lòng chỉnh sửa với nhiều thông tin hơn. Các câu trả lời chỉ dành cho mã và "thử cái này" không được khuyến khích, vì chúng không chứa nội dung có thể tìm kiếm và không giải thích lý do tại sao một người nào đó nên "thử cái này". Chúng tôi nỗ lực ở đây để trở thành một nguồn tài nguyên cho kiến ​​thức.
Brian Tompsett - 汤

1
Downvote vì chỉ lặp lại các câu trả lời đúng đã được đưa ra từ lâu mà không cần thêm bất kỳ giá trị bổ sung nào
Thức ăn gia súc

-1

nếu bạn đang đọc từ tập tin thì điều này có thể giúp bạn

              try{
             InputStream inputStream = (InputStream) mnpMainBean.getUploadedBulk().getInputStream();
             BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
             String line;
             //Ref:03
             while ((line = br.readLine()) != null) {
                if (line.matches("[A-Z],\\d,(\\d*,){2}(\\s*\\d*\\|\\d*:)+")) {
                     String[] splitRecord = line.split(",");
                     //do something
                 }
                 else{
                     br.close();
                     //error
                     return;
                 }
             }
                br.close();

             }
         }
         catch (IOException  ioExpception){
             logger.logDebug("Exception " + ioExpception.getStackTrace());
         }
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.