Regex для захвата групп и игнорирования последних двух символов, где один необязательный - PullRequest
1 голос
/ 05 февраля 2020

Мне нужно захватить две группы из входной строки. Значения отличаются по структуре по мере поступления.

Ниже приведены примеры входящих строк:

Comment = "This is a comment";

NumericValue = 123456;

Что Я пытаюсь выполнить sh, чтобы получить строковое значение слева от знака равенства как одну группу, а значение после знака равенства - как вторую группу. Точку с запятой никогда не следует включать.

Предупреждение: если вторая группа является строкой, кавычки с каждого конца не должны включаться в эту группу захвата.

Ожидаемые результаты будут :

  1. Комментарий = "Это комментарий";
  2. группа ключей => Комментарий
  3. группа значений => Это комментарий
  4. NumericValue = 123456;
  5. группа ключей => NumericValue
  6. группа значений => 123456

что у меня так далеко. Это прекрасно работает для захвата числового значения c, но оставляет строковые двойные кавычки при захвате строкового значения.

(?<key>\w+)\s*=\s*(?:[\"]?)(?<group>.+(?:(?=[\"]?;)))

EDIT

Применяя регулярное выражение к строковому значению, оно должно разрешать захват точек с запятой и двойных кавычек в строке и игнорировать только закрывающие.

Итак, если у нас есть ввод:

Comment = "This is a "comment"; This is still a comment";

Вторая группа захвата должна быть:

This is a "comment"; This is still a comment

Ответы [ 3 ]

2 голосов
/ 05 февраля 2020

Можно использовать чередование, где вам нужно будет проверить группу 2 или группу 3:

(?<key>\w+)\h*=\h*(?:"(.*?)"|([^"\r\n]+));$
  • (?<key>\w+) Группа key совпадение с 1 + словами символов
  • \h*=\h* Соответствует = между необязательными горизонтальными пробельными символами
  • (?: Группа без захвата
  • "(.+?)" Захват в группе 2 1+ раз с любым символом между "
    • | Или
    • ([^"\r\n]+) Группа захвата 3, совпадение 1+ раз с любым символом, кроме " или новой строкой
  • ); Закрыть группу без захвата и сопоставить ;
  • $ Конец строки

Regex demo

In Java

String regex = "(?<key>\\w+)\\h*=\\h*(?:\"(.*?)\"|([^\"\\r\\n]+));$";
1 голос
/ 05 февраля 2020

Отредактировано на основе комментария для включения ; и " в комментарии согласно приведенным примерам:

(?<key>\w+)\s*=\s*(?:[\"]?)(?<value>((")(?!;?$)|;(?!$)|[^;"])+)"?;?$

Следующий дополнительно не позволяет ; или " появляются в цифре c текст. Однако, чтобы включить это, мне пришлось переименовать группы захвата, потому что имя нельзя использовать более чем для одной группы.

(?<key>\w+)\s*=\s*((?:")(?<valueT>((")(?!;?$)|;(?!$)|[^;"])+)";?$|(?<valueN>[^;"]+);?$)

Вот класс, который тестирует его.

Для удобства чтения я разделил регулярные выражения key и value в классе. Я добавил тестовые примеры в метод в классе. Однако, это все еще не относится к случаю числового c текста, содержащего ; или ". Кроме того, линию необходимо обрезать перед тем, как подвергнуть тесту шаблона (который я думаю, что это возможно).

public class NameValuePairRegex{

    public static void main( String[] args ){
        String SPACE = "\\s*";
        String EQ = "=";
        String OR = "|";

        /* The original regex tried by you (for comparison). */
        String orig = "(?<key>\\w+)\\s*=\\s*(?:[\\\"]?)(?<value>.+(?:(?=;)))";

        String key = "(?<key>\\w+)";
        String valuePatternForText = "(?:\")(?<valueT>((\")(?!;?$)|;(?!$)|[^;\"])+)\";?$";
        String valuePatternForNumbers = "(?<valueN>[^;\"]+);?$";
        String p = key + SPACE + EQ + SPACE + "(" + valuePatternForText + OR + valuePatternForNumbers + ")";

        Pattern nvp = Pattern.compile( p );
        System.out.println( nvp.pattern() );
        print( input(), nvp );
    }

    private static void print( List<String> input, Pattern ep ) {
        for( String e : input ) {
            System.out.println( e );
            Matcher m = ep.matcher( e );
            boolean found = m.find();
            if( !found ) {
                System.out.println( "\t\tNo match" );
                continue;
            }

            String valueT = m.group( "valueT" );
            String valueN = m.group( "valueN" );

            System.out.print( "\t\t" + m.group( "key" ) + " -> " + ( valueT == null ? "" : valueT ) + " " + ( valueN == null ? "" : valueN ) );
            System.out.println(  );
        }

    }

    private static List<String> input(){
        List<String> neg = new ArrayList<>();
        Collections.addAll( neg, 
                "Comment = \"This is a comment\";",
                "Comment = \"This is a comment with semicolon ;\";", 
                "Comment = \"This is a comment with semicolon ; and quote\"\";",
                "Comment = \"This is a comment\"", 
                "Comment = \"This is a \"comment\"; This is still a comment\";",
                "NumericValue = 123456;",
                "NumericValue = 123;456;",
                "NumericValue = 123\"456;",
                "NumericValue = 123456" );

        return neg;
    }

}

Оригинальный ответ:

Следующее измененное регулярное выражение выполняет указанные вами требования. Я добавил исключение ; и " из части значения.

Оригинал, который вы пробовали:

(?<key>\w+)\s*=\s*(?:[\"]?)(?<group>.+(?:(?=[\"]?;)))

Измененный:

(?<key>\w+)\s*=\s*(?:[\"]?)(?<value>[^;"]+)
0 голосов
/ 05 февраля 2020

Регулярные выражения - это весело, но посмотрите, насколько это легко и просто прочитать без использования регулярного выражения:

int equals = s.indexOf('=');

String key = s.substring(0, equals).trim();

String value = s.substring(equals + 1).trim();
if (value.endsWith(";")) {
    value = value.substring(0, value.length() - 1).trim();
}
if (value.startsWith("\"") && value.endsWith("\"")) {
    value = value.substring(1, value.length() - 1);
}

Не думайте, что в этом случае используется больше строк кода, чем в регулярном выражении. что это медленнее. Строки кода, выполняемые внутренним движком регулярных выражений, будут намного превышать приведенный выше код.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...