Групи з назвою Regex на Java


173

Наскільки я розумію, що java.regexпакет не підтримує названі групи ( http://www.regular-expressions.info/named.html ), тому хто-небудь може вказати мені на сторонні бібліотеки, які це роблять?

Я дивився на jregex, але його останній реліз був у 2002 році, і він не працював для мене (правда, я спробував лише коротко) під Java5.


3
Ваше розуміння невірно. JDK7 обробляє названі групи.
tchrist

2
@tchrist У 2009 році JDK7 не було.
Alex78191

Відповіді:


275

( Оновлення : серпень 2011 р. )

Як згадує геофлан у своїй відповіді , Java 7 тепер підтримує названі групи .
tchrist вказує у коментарі, що підтримка обмежена.
Він детально описує обмеження у своїй чудовій відповіді " Помічник Java Regex "

Підтримка групової групи під назвою Java 7 була представлена ​​ще у вересні 2010 року в блозі Oracle .

В офіційному випуску Java 7 конструктами для підтримки названої групи захоплення є:

  • (?<name>capturing text) визначити названу групу "ім'я"
  • \k<name> для відновлення названої групи "ім'я"
  • ${name} для посилання на захоплену групу в рядку заміни Матчера
  • Matcher.group(String name) повернути захоплений вхідний податок заданою "названою групою".

Іншими альтернативами для попередньої Java 7 були:


( Оригінальна відповідь : січень 2009 р , тепер наступні два посилання розірвані)

Ви не можете посилатися на названу групу, якщо ви не кодуєте власну версію Regex ...

Саме це і зробив Горбуш2 у цій темі .

Regex2

(обмежена реалізація, як знову вказує tchrist , оскільки вона виглядає лише для ідентифікаторів ASCII. tchrist деталізує обмеження як:

тільки мати змогу мати одну названу групу на одне ім’я (над якою ви не завжди маєте контроль!) і не мати змоги використовувати їх для регекс-рекурсії.

Примітка. Ви можете знайти справжні приклади рекурсії в регулярних регексах Perl та PCRE, як зазначено в Regexp Power , специфікаціях PCRE та узгодженні рядків із слайдом збалансованих дужок )

Приклад:

Рядок:

"TEST 123"

RegExp:

"(?<login>\\w+) (?<id>\\d+)"

Доступ

matcher.group(1) ==> TEST
matcher.group("login") ==> TEST
matcher.name(1) ==> login

Замініть

matcher.replaceAll("aaaaa_$1_sssss_$2____") ==> aaaaa_TEST_sssss_123____
matcher.replaceAll("aaaaa_${login}_sssss_${id}____") ==> aaaaa_TEST_sssss_123____ 

(витяг з реалізації)

public final class Pattern
    implements java.io.Serializable
{
[...]
    /**
     * Parses a group and returns the head node of a set of nodes that process
     * the group. Sometimes a double return system is used where the tail is
     * returned in root.
     */
    private Node group0() {
        boolean capturingGroup = false;
        Node head = null;
        Node tail = null;
        int save = flags;
        root = null;
        int ch = next();
        if (ch == '?') {
            ch = skip();
            switch (ch) {

            case '<':   // (?<xxx)  look behind or group name
                ch = read();
                int start = cursor;
[...]
                // test forGroupName
                int startChar = ch;
                while(ASCII.isWord(ch) && ch != '>') ch=read();
                if(ch == '>'){
                    // valid group name
                    int len = cursor-start;
                    int[] newtemp = new int[2*(len) + 2];
                    //System.arraycopy(temp, start, newtemp, 0, len);
                    StringBuilder name = new StringBuilder();
                    for(int i = start; i< cursor; i++){
                        name.append((char)temp[i-1]);
                    }
                    // create Named group
                    head = createGroup(false);
                    ((GroupTail)root).name = name.toString();

                    capturingGroup = true;
                    tail = root;
                    head.next = expr(tail);
                    break;
                }

обидва посилання вище, здається, порушені?
Йонас

Цей код баггі. Він шукає ідентифікатори ASCII. Це неправильно. Слід шукати все, що дозволяє Java в ідентифікаторі !!
tchrist

1
Просто FYI, оскільки ви здаєтеся таким сумлінним, обмежена частина стосується не стільки імен ASCII проти Unicode, скільки лише того, щоб мати змогу мати одну названу групу на одне ім’я (над якою ви не завжди маєте контроль!) І не в змозі використовувати їх для регексу регексу.
tchrist

@tchrist: дякую за цю точність (в комплекті). Я також додав посилання на вашу зоряну відповідь на тему "помічник Java Regex" (оновлено).
VonC

У Java немає методу matcher.name (int index) для об'єкта Matcher ??
ot0


27

Так, але його безладно хакерські сонце класи. Є більш простий спосіб:

http://code.google.com/p/named-regexp/

name-regexp - це тонка обгортка для стандартної реалізації регулярних виразів JDK, з єдиною метою обробляти названі групи захоплення у стилі .net: (? ...).

Його можна використовувати з Java 5 і 6 (використовуються дженерики).

Java 7 буде обробляти іменовані групи захоплення, тому цей проект не повинен тривати.


1
Шкода, що це не можна використовувати зсередини GWT.
Сакураба

4
Перегляньте вилку GitHub цього проекту, яка виправляє кілька помилок у оригіналі. Він також проводиться в Maven Central.
tony19

1
У моєму випадку лише обережно, вилка tony19 на Github не працює на Android, як відомо, на 0.1.8.
Чак Д

2
@RubberMallet, Проблема, пов’язана з Android, тепер виправлена і складе 0,1,9.
tony19


2

Для тих, хто працює перед програмою java7, названі групи підтримуються joni (порт порту бібліотеки Oniguruma regexp). Документація рідка, але вона спрацювала добре для нас.
Бінарні файли доступні через Maven ( http://repository.codehaus.org/org/jruby/joni/joni/ ).


Мене дуже цікавить варіант joni, про який згадував Райан вище - чи є у вас фрагменти коду за допомогою названих груп захоплення - мені вдалося отримати базову відповідність та пошук, щоб правильно працювати - але я не бачу, до якого методу я б скористався отримати доступ до імен групи або отримати значення захоплення за допомогою імені групи.
мальчик

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.