Именованные группы Regex в Java

173

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

Я посмотрел на jregex, но его последний выпуск был в 2002 году, и он не работал для меня (по общему признанию, я только попробовал кратко) под java5.

Дэн
источник
3
Ваше понимание неверно. JDK7 обрабатывает именованные группы.
tchrist
2
@tchrist В 2009 году не было JDK7.
Alex78191

Ответы:

276

( Обновление : август 2011 г. )

Как упоминает Джеффлан в своем ответе , Java 7 теперь поддерживает именованные группы .
В комментарии Трист указывает, что поддержка ограничена.
Он подробно описывает ограничения в своем великолепном ответе « Java Regex Helper »

Поддержка именованных групп Java 7 regex была представлена ​​еще в сентябре 2010 года в блоге Oracle .

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

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

Другие альтернативы для pre-Java 7 были:


( Оригинальный ответ : январь 2009 г. , следующие две ссылки теперь не работают)

Вы не можете ссылаться на именованную группу, если вы не написали свою собственную версию Regex ...

Именно это и сделал Gorbush2 в этой теме .

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;
                }
VonC
источник
обе ссылки выше вроде битые?
Джонас
Этот код глючит. Он ищет идентификаторы ASCII. Это неверно. Следует искать все, что Java позволяет в идентификаторе!
tchrist
1
Просто к вашему сведению, поскольку вы выглядите очень добросовестно, ограниченная часть касается не столько имен ASCII против Unicode, сколько возможности иметь только одну именованную группу для одного и того же имени (которую вы не всегда можете контролировать!) И не в состоянии использовать их для рекурсии в регулярных выражениях.
tchrist
@tchrist: спасибо за эту точность (в комплекте). Я также добавил ссылку на ваш звездный ответ на тему «Помощник по Java Regex» (upvoted).
VonC
В Java нет метода matcher.name (int index) для объекта Matcher.
ot0
27

Да, но это грязное хакерство. Есть более простой способ:

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

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

Какую проблему вы получаете с Jregex ? Это работало хорошо для меня под java5 и java6.

Jregex хорошо справляется с этой задачей (даже если последняя версия 2002 года), если только вы не хотите ждать javaSE 7 .

Брайан Клозел
источник
2

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

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

Немного старый вопрос, но мне это тоже понадобилось, и что приведенные выше предложения были неадекватны - и поэтому я сам разработал тонкую оболочку: https://github.com/hofmeister/MatchIt

Хенрик Хофмайстер
источник