Java'da Bir Değer Çıkarmak için Normal İfadeler Kullanma


169

Kaba formda birkaç dizeleri var:

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

Java Regex sınıflarını kullanarak [bazı sayı] metni ayıklamak istiyorum.

Kabaca hangi düzenli ifadeyi kullanmak istediğimi biliyorum (tüm öneriler hoş geldiniz). Gerçekten ilgilendiğim regex dizesini almak ve [bazı sayı] değerini üretmek için kaynak verilerde kullanmak için Java çağrıları vardır.

EDIT: Ben sadece tek bir [bazı sayı] (temelde, ilk örnek) ilgileniyorum eklemek gerekir. Kaynak dizeleri kısa ve ben [bazı sayı] birden fazla oluşumlar için bakmayacağım.


11
... ve şimdi araştırmaya gidiyorum. Bakalım SO, kendim çözmeden önce benim için bir cevap alabilir mi? :-P
Craig Walker

Bu bir bankacılık / yatırım / ticaret şirketi yazılım mühendisliği için bir röportaj soruları değil mi? : P
ennth

@ennth Hayır, yakın bile değil! Küçük bir web sitesinde üretim kodu içindi ... birçok ay önce.
Craig Walker

1
lanet olsun ben sadece birkaç gün önce JP Morgan Chase Yazılım Mühendisliği kodlama sınavında hemen hemen aynı soru soruldu: P
ennth

Yanıtlar:


316

Tam örnek:

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

İlk sayıyı aradığınızdan, böyle normal ifadeyi kullanabilirsiniz:

^\D+(\d+).*

ve m.group(1)size ilk sayıyı döndürür. İmzalı numaraların eksi işareti içerebileceğini unutmayın:

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

62
Patter nesnesini yeniden kullanmayı unutmayın. Pıtırtı derlemek çok zaman alır.
Rastislav Komara

14
Kabul. Genellikle kalıbı özel bir statik son kalıp olarak tanımlayabilirim PATTERN = Pattern.compile ("..."); Ama bu sadece benim.
Allain Lalonde

6
Desen p = Pattern.compile ("\\ d +") kullanabilirsiniz;
javaMan

15
Açıklama olmadan bu kötü bir cevaptır.
Martin Spamer

Eşleştiriciyi de yeniden kullanabilirsiniz. Her kullanım arasında Eşleştiricinin reset () yöntemini çağırın. Eşleştiriciyi birden çok eşzamanlı iş parçacığında paylaşıyorsanız işlemi senkronize etmelisiniz.
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());
        }
    }
}

Çıktı:

1234
789
2345

Soru özellikle sadece İLK sayıların oluşmasını ister.
NoBrainer

34

Allain temelde java koduna sahiptir, bu yüzden kullanabilirsiniz. Ancak, ifadesi yalnızca sayılarınızın önünde yalnızca bir kelime karakteri akışı varsa eşleşir .

"(\\d+)"

ilk basamak dizesini bulabilmelidir. İlk basamak dizisi olacağından eminseniz, bundan önce ne olduğunu belirtmenize gerek yoktur. Benzer şekilde, siz istemedikçe, bundan sonra ne olduğunu belirtmenin bir anlamı yoktur. Sadece sayıyı istiyorsanız ve bir veya daha fazla basamağın ilk dizesi olacağından eminseniz, ihtiyacınız olan tek şey budur.

Boşluklarla dengelenmesini beklerseniz, belirtmek daha da farklı olacaktır.

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

daha iyi olabilir.

Üç parçaya da ihtiyacınız varsa, bu yapılacaktır:

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

EDIT Allain ve Jack tarafından verilen İfadeler, rakamları yakalamak için basamak olmayan bazı alt kümeleri belirtmeniz gerektiğini önerir . Eğer regex motoruna aradığınızı söylerseniz \d, rakamlardan önce her şeyi görmezden gelir. J veya A'nın ifadesi ise uyuyor Kalıbınızı, sonra tüm maç eşittir giriş dizesi . Ve bunu belirtmek için bir sebep yok. Tamamen görmezden gelinmediği takdirde, muhtemelen temiz bir maç yavaşlar.


Axemans hipotezini örnek bir test yaparak ve onun A / J çözümünün performansını kontrol ederek test edebilirsiniz.
anjanb

Dizenin başlangıcını ve sonunu belirtmeniz gerekmez. Aksi halde sözdizimine uymasa bile 124xxx123xxx gibi şeyler eşleştirilir mi? Yoksa ^ ve $ örtük mü?
Allain Lalonde

Allain, seninki de başarısız olur. Sen ve Jack, rakam olmayan karakterlerin rakamlardan önce geleceğini varsayarsınız. Ya yaparlar ya da yapmazlar. Bu durumda, bu ifadelerin hiçbiri bu satırı ayrıştırmaz. Belirtildiği gibi , rakamların deseninin yeterli olduğunu tekrar ediyorum .
Axeman

11

Pattern'e ek olarak , Java String sınıfında düzenli ifadelerle çalışabilecek çeşitli yöntemler de vardır, bu durumda kod şöyle olacaktır:

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

Burada \\Drakam olmayan bir karakter vardır.


10

Java 1.4 ve sonraki sürümlerde:

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

Bu işlev dizeden eşleşen tüm dizileri toplar. Bu örnekte, tüm e-posta adresleri dizeden alınır.

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

İçin message = "adf@gmail.com, <another@osiem.osiem>>>> lalala@aaa.pl"bu 3 unsurların listesi yaratacaktır.


3

Bunun gibi bir şey yapmayı deneyin:

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

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

3
-1. Çünkü .+açgözlülükle tükettiğini karakterler, \d+sadece yakalar "3"dan "123". Ayrıca, dizgi değişmezlerinin içinde ters eğik çizgiden kaçmanız gerekir (örneğin derlenmeyecektir).
Bart Kiers

3

Basit Çözüm

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

Util Sınıfında Çözüm

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

Bak StringTokenizer kullanarak yapabilirsiniz

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

Bu sayısal verileri üç farklı değişkene aldığımızdan, bu verileri kodun herhangi bir yerinde kullanabiliriz (daha fazla kullanım için)


0

Peki [^\\d]*([0-9]+[\\s]*[.,]{0,1}[\\s]*[0-9]*).*Bence fraksiyonel bölümü ile sayılar ilgiyi gösterecektir. Beyaz boşluklar ve ,mümkün olduğunca ayırıcı ekledim. Yüzen dahil bir dize numaraları almaya çalışıyorum ve kullanıcı bir hata yapabilir ve sayı yazarken beyaz boşluklar dahil dikkate alarak.


0

Bazen java.lang.String dosyasında bulunan basit .split ("REGEXP") yöntemini kullanabilirsiniz. Örneğin:

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
Lütfen daha fazla bilgi ile düzenleyin. Yalnızca kod ve "bunu dene" yanıtları önerilmez çünkü bunlar aranabilir içerik içermez ve birisinin neden "bunu denemesi" gerektiğini açıklamaz. Burada bilgi kaynağı olmak için gayret gösteriyoruz.
Brian Tompsett - 莱恩 莱恩

1
Herhangi bir ek değer eklemeden uzun zaman önce verilen doğru cevapları tekrarlamak için downvote
Yem

-1

dosyadan okuyorsanız, bu size yardımcı olabilir

              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());
         }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.