Використання регулярних виразів для отримання значення в Java


169

У мене є кілька рядків у грубій формі:

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

Я хочу витягнути текст у [деякій кількості] за допомогою класів Java Regex.

Я приблизно знаю, який регулярний вираз я хочу використовувати (хоча всі пропозиції вітаються). Мене справді цікавлять - це заклики Java взяти рядок regex і використовувати його у вихідних даних для отримання значення [деякого числа].

EDIT: Я повинен додати, що мене цікавить лише одна [деяка кількість] (в основному, перша інстанція). Джерельні рядки короткі, і я не збираюсь шукати декілька випадків [деякої кількості].


11
... і зараз я переходжу до досліджень. Давайте подивимось, чи можу я отримати відповідь за мене, перш ніж я сам це зрозуміти. :-P
Крейг Уокер

це були питання інтерв'ю у банківській / інвестиційній / торговій компанії з інженерії програмного забезпечення, чи не так? : P
ennth

@ Дев'ятий Нопе, навіть не близько! Це було для виробничого коду на веб-сайті малого бізнесу ... багато місяців тому.
Крейг Уокер

1
чорт забираю, мені було задано майже такий самий точний запитання на іспиті з кодування JP Morgan Chase Software Engineering декілька днів тому: P
ennth

Відповіді:


316

Повний приклад:

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

Оскільки ви шукаєте перший номер, ви можете використовувати такий regexp:

^\D+(\d+).*

і m.group(1)поверне вам перший номер. Зауважте, що підписані номери можуть містити знак мінус:

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

62
Не забудьте повторно використовувати об’єкт Patter. Складання малюнка займає величезну кількість часу.
Растислав Комара

14
Домовились. Зазвичай я б визначав шаблон як приватний статичний кінцевий шаблон PATTERN = Pattern.compile ("..."); Але це тільки я.
Аллайн Лалонде

6
ми можемо просто використовувати Pattern p = Pattern.compile ("\\ d +");
javaMan

15
Без пояснень це погана відповідь.
Мартін Спамер

Ви також можете повторно використовувати Матч. Виклик методу скидання () Matcher між кожним використанням. Якщо ви спільно використовуєте матчер на кілька одночасних потоків, вам слід синхронізувати операцію.
Маркес

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

Вихід:

1234
789
2345

Питання спеціально задає лише ПЕРШЕ виникнення чисел.
NoBrainer

34

Аллайн в основному має код java, тому ви можете ним скористатися. Однак його вираз відповідає лише тому, що вашим цифрам передує лише потік символів слова.

"(\\d+)"

має бути в змозі знайти перший рядок цифр. Не потрібно вказувати, що перед цим, якщо ви впевнені, що це буде перший рядок цифр. Крім того, немає жодної користі вказувати, що після нього, якщо ви цього не хочете. Якщо ви просто хочете число і впевнені, що це буде перший рядок з однієї або декількох цифр, то це все, що вам потрібно.

Якщо ви очікуєте, що це буде компенсовано пробілами, це зробить його ще більш чітким вказувати

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

може бути краще.

Якщо вам потрібні всі три частини, це зробить:

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

EDIT Вирази Аллайна та Джека припускають, що вам потрібно вказати деякий підмножина нецифрових знаків для того, щоб фіксувати цифри . Якщо ви скажете двигуну регулярного вибору, який ви шукаєте, \dвін буде ігнорувати все перед цифрами. Якщо вираз J або А в пристосовує свій зразок, то весь матч дорівнює в рядку введення . І немає ніяких причин вказувати це. Це, ймовірно, сповільнює чисту відповідність, якщо її повністю не ігнорувати.


ви можете перевірити гіпотезу Аксемана, провівши зразок тесту та перевіривши ефективність його рішення проти A / J.
anjanb

Чи не потрібно вказувати початок і кінець рядка. Інакше такі речі, як 124xxx123xxx, відповідатимуть, хоча це не вписується у його синтаксис? Або ^ і $ неявні?
Аллайн Лалонда

Аллайн, і твій теж невдалий. Ви з Джеком робите припущення, що нецифрові символи передують цифрам. Вони або роблять, або ні. У цьому випадку жоден із цих виразів не буде аналізувати цей рядок. Повторюю, що як зазначено , шаблону для цифр достатньо.
Axeman

11

Окрім шаблону , клас Java String також має кілька методів, які можуть працювати з регулярними виразами, у вашому випадку код буде:

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

де \\Dнецифровий символ.


10

У Java 1.4 і новіших версій:

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

Ця функція збирає всі відповідні послідовності з рядка. У цьому прикладі всі адреси електронної пошти беруть з рядка.

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

Для message = "adf@gmail.com, <another@osiem.osiem>>>> lalala@aaa.pl"нього буде створено Список з 3 елементів.


3

Спробуйте зробити щось подібне:

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

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

3
-1. Оскільки .+жадібно споживає символів, \d+лише захоплює "3"з "123". Крім того, всередині рядкових літералів вам потрібно уникнути зворотної косої риси (ваш приклад не складеться).
Барт Кіерс

3

Просте рішення

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

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

Подивіться, ви можете це зробити за допомогою 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);
}

Оскільки ми беремо ці числові дані у три різні змінні, ми можемо використовувати ці дані в будь-якому місці коду (для подальшого використання)


0

Як щодо того, [^\\d]*([0-9]+[\\s]*[.,]{0,1}[\\s]*[0-9]*).*я думаю, що це буде дбати про числа з дробовою частиною. Я включив пробіли і включив ,як можливий роздільник. Я намагаюся витягнути числа з рядка, включаючи плаваючі, і враховуючи, що користувач може допустити помилку і включити пробіли під час введення номера.


0

Іноді можна використовувати простий .split ("REGEXP") метод, доступний у java.lang.String. Наприклад:

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
Відредагуйте додаткові відомості. Відповіді, що містять лише коди, та "спробувати це" не рекомендують, оскільки вони не містять вмісту, який можна шукати, і не пояснюють, чому хтось повинен "спробувати це". Ми докладаємо зусиль, щоб бути ресурсом для знань.
Брайан Томпсетт - 汤 莱恩

1
Довідка за просто повторення правильних відповідей, даних давно, не додаючи додаткових цінностей
Корм

-1

якщо ви читаєте з файлу, то це може вам допомогти

              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());
         }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.