Menggunakan Ekspresi Reguler untuk Mengekstrak Nilai di Jawa


169

Saya memiliki beberapa string dalam bentuk kasar:

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

Saya ingin mengekstrak teks dalam [beberapa angka] menggunakan kelas Java Regex.

Saya tahu kira-kira ungkapan reguler apa yang ingin saya gunakan (meskipun semua saran diterima). Yang saya benar-benar tertarik adalah panggilan Java untuk mengambil string regex dan menggunakannya pada sumber data untuk menghasilkan nilai [beberapa angka].

EDIT: Saya harus menambahkan bahwa saya hanya tertarik pada satu [beberapa nomor] (pada dasarnya, contoh pertama). Sumber string pendek dan saya tidak akan mencari beberapa kejadian [beberapa nomor].


11
... dan sekarang saya pergi untuk penelitian. Mari kita lihat apakah SO bisa mendapatkan jawaban untuk saya sebelum saya mengetahuinya sendiri. :-P
Craig Walker

ini adalah pertanyaan wawancara di perusahaan perbankan / investasi / perdagangan untuk rekayasa perangkat lunak bukan? : P
ennth

Sungguh tidak, bahkan tidak dekat! Itu untuk kode produksi di situs bisnis kecil ... beberapa bulan yang lalu.
Craig Walker

1
sialan aku ditanya pertanyaan yang hampir sama persis pada ujian pengkodean Rekayasa Perangkat Lunak JP Morgan Chase hanya beberapa hari yang lalu: P
ennth

Jawaban:


316

Contoh lengkap:

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

Karena Anda mencari nomor pertama, Anda dapat menggunakan regexp tersebut:

^\D+(\d+).*

dan m.group(1)akan mengembalikan Anda nomor pertama. Perhatikan bahwa angka yang ditandatangani dapat berisi tanda minus:

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

62
Jangan lupa untuk menggunakan kembali objek Patter. Menyusun derai membutuhkan banyak waktu.
Rastislav Komara

14
Sepakat. Biasanya saya akan mendefinisikan polanya sebagai POLA pola final statis pribadi = Pattern.compile ("..."); Tapi itu hanya aku.
Allain Lalonde

6
kita cukup menggunakan Pattern p = Pattern.compile ("\\ d +");
javaMan

15
Tanpa penjelasan, ini adalah jawaban yang buruk.
Martin Spamer

Anda juga dapat menggunakan kembali Pencocokan. Sebut metode reset () yang cocok antara setiap penggunaan. Jika Anda berbagi pencocokan di beberapa utas bersamaan, Anda harus menyinkronkan operasi.
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());
        }
    }
}

Keluaran:

1234
789
2345

Pertanyaannya secara spesifik hanya menanyakan angka yang PERTAMA terjadi.
NoBrainer

34

Allain pada dasarnya memiliki kode java, jadi Anda bisa menggunakannya. Namun, ekspresinya hanya cocok jika nomor Anda hanya didahului oleh aliran karakter kata.

"(\\d+)"

harus dapat menemukan string angka pertama. Anda tidak perlu menentukan apa yang sebelumnya, jika Anda yakin itu akan menjadi string digit pertama. Demikian juga, tidak ada gunanya untuk menentukan apa setelahnya, kecuali jika Anda menginginkannya. Jika Anda hanya menginginkan nomornya, dan yakin itu akan menjadi string pertama dari satu atau lebih digit maka itu saja yang Anda butuhkan.

Jika Anda mengharapkannya diimbangi dengan spasi, itu akan membuatnya lebih berbeda untuk ditentukan

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

mungkin lebih baik.

Jika Anda membutuhkan ketiga bagian, ini akan melakukan:

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

EDIT Ekspresi yang diberikan oleh Allain dan Jack menunjukkan bahwa Anda perlu menentukan beberapa subset non-digit untuk mendapatkan digit . Jika Anda memberi tahu mesin regex yang Anda cari \dmaka itu akan mengabaikan semuanya sebelum angka. Jika ekspresi J atau A cocok dengan pola Anda, maka seluruh kecocokan sama dengan string input . Dan tidak ada alasan untuk menentukannya. Mungkin memperlambat pertandingan bersih, jika tidak diabaikan sepenuhnya.


Anda dapat menguji hipotesis Axemans dengan menjalankan uji sampel dan memeriksa kinerja solusi vs. A / J-nya.
anjanb

Apakah Anda tidak perlu menentukan awal dan akhir string. Kalau tidak, hal-hal seperti 124xxx123xxx akan cocok meskipun tidak cocok dengan sintaksnya? Atau ^ dan $ implisit?
Allain Lalonde

Allain, milikmu akan gagal juga. Anda dan Jack membuat asumsi bahwa karakter non-digit akan mendahului digit. Mereka melakukannya atau tidak. Dalam hal ini, tidak ada ekspresi yang akan menguraikan baris ini. Saya ulangi seperti yang ditentukan , pola untuk digit sudah cukup.
Axeman

11

Selain Pola , kelas Java String juga memiliki beberapa metode yang dapat bekerja dengan ekspresi reguler, dalam kasus Anda kodenya adalah:

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

di mana \\Dkarakter non-digit.


10

Di Jawa 1.4 dan lebih tinggi:

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

Fungsi ini mengumpulkan semua urutan pencocokan dari string. Dalam contoh ini dibutuhkan semua alamat email dari string.

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

Untuk message = "adf@gmail.com, <another@osiem.osiem>>>> lalala@aaa.pl"itu akan membuat Daftar 3 elemen.


3

Coba lakukan sesuatu seperti ini:

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

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

3
-1. Karena .+rakus mengkonsumsi karakter, \d+hanya menangkap "3"dari "123". Juga, di dalam string literal, Anda harus menghindari backslash (contoh Anda tidak akan dikompilasi).
Bart Kiers

3

Solusi Sederhana

// 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
}

Solusi di Kelas 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

Lihat, Anda bisa melakukannya menggunakan 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);
}

Karena kami mengambil data numerik ini menjadi tiga variabel yang berbeda, kami dapat menggunakan data ini di mana saja dalam kode (untuk penggunaan lebih lanjut)


0

Bagaimana kalau [^\\d]*([0-9]+[\\s]*[.,]{0,1}[\\s]*[0-9]*).*saya pikir itu akan mengurus angka dengan bagian fraksional. Saya menyertakan spasi putih dan dimasukkan ,sebagai pemisah mungkin. Saya mencoba mengeluarkan angka dari string termasuk float dan mempertimbangkan bahwa pengguna mungkin membuat kesalahan dan memasukkan spasi putih saat mengetik nomor.


0

Terkadang Anda dapat menggunakan metode .split ("REGEXP") sederhana yang tersedia di java.lang.String. Sebagai contoh:

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
Harap edit dengan informasi lebih lanjut. Jawaban khusus kode dan "coba ini" tidak disarankan, karena tidak mengandung konten yang dapat ditelusuri, dan jangan jelaskan mengapa seseorang harus "mencoba ini". Kami berusaha di sini untuk menjadi sumber pengetahuan.
Brian Tompsett - 汤 莱恩

1
Downvote hanya untuk mengulangi jawaban yang benar yang telah lama diberikan tanpa menambahkan nilai tambahan
Hijauan

-1

jika Anda membaca dari file maka ini dapat membantu Anda

              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());
         }
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.