Как объединить регулярные выражения для сопоставления строк с разделителями и без них? - PullRequest
0 голосов
/ 04 марта 2019

У меня есть строки, подобные следующим, упомянутым как Ввод , которые необходимо обработать и преобразовать в пары name / value, как указано ниже:

Вход: FOO = BAR=BAZ Выход: name='FOO', value='BAR=BAZ'

Вход: FOO = BAR Выход: name='FOO', value='BAR'

Вход: FOO = Выход: name='FOO', value=''

Вход: = BAR=BAZ Выход: name='', value='BAR:BAZ'

Вход: = BAR Выход: name='', value='BAR'

Ввод: FOO Выход: name='FOO', value=''

Обратите внимание, что разделитель либо =или :.Отсутствие разделителя также возможно.

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

regexp {^\s*(.*?)\s*[=:]\s*(.*?)\s*$} $setting -> name value

if {![info exists name]} {
    set name {}
}

if {![info exists value]} {
    set value {}
}

puts "name='$name', value='$value'"

, для которого он возвращает

Выход: name='', value=''

вместо

Выход: name='FOO', value=''

Последний случай может быть охвачен регулярным выражением ниже:

regexp {^\s*(.*?)\s*$} $setting -> name value

Как эти регулярные выражения можно объединить, чтобы иметь только одно регулярное выражение, охватывающее все случаи?

Ответы [ 3 ]

0 голосов
/ 04 марта 2019

Мне непонятно, почему вы настаиваете на этом с regexp.Когда ваше регулярное выражение становится слишком сложным, возможно, пришло время использовать другой подход.Предполагая, что в вашей строке не будет символов NUL, вы могли бы сделать это вместо этого:

lassign [split [regsub {\s*[:=]\s*} [string trim $setting] \0] \0] name value

Обрезка строки избавляет от любого окружающего пробела.Затем разделитель и все окружающие пробелы заменяются символом NUL.Наконец, результат разбивается на два для этого символа NUL, и две части назначаются переменным имени и значения.

Согласно моим измерениям, этот метод более чем в два раза быстрее, чем вариант регулярного выражения.

0 голосов
/ 05 марта 2019
set tests {{FOO = BAR=BAZ} {FOO = BAR} {FOO =} {= BAR=BAZ} {= BAR} FOO}
foreach test $tests {
    # expanded regex with commentary
    regexp {(?x)
        (.*?)               # the left-hand side, may be empty
        (?:                 # start a group, but do not capture it
            \s*[:=]\s*      # the separator
            (.*)            # the value
        )?                  # end the group, and it is optional
        $                   # until the end of line: this is required because the
                            # whole regex is non-greedy due to the first
                            # quantifier being non-greedy. Without the anchor,
                            # the 2nd capture will always be the empty string.
    } $test -> var value

    puts "name='$var', value='$value'"
}

выходы

name='FOO', value='BAR=BAZ'
name='FOO', value='BAR'
name='FOO', value=''
name='', value='BAR=BAZ'
name='', value='BAR'
name='FOO', value=''
0 голосов
/ 04 марта 2019

Как эти регулярные выражения можно объединить, чтобы иметь только одно регулярное выражение, охватывающее все случаи?

Первое уже включает второе :) Но ваше более обширное регулярное выражение не может соответствоватьпоследний случай (FOO), потому что он вообще не содержит символов-разделителей.Посмотрите результат [regexp], который будет 0.

. Учитывайте следующее:

 ^\s*([^=:]*)\s*[=:]?\s*(.*)\s*$

Это должно охватывать все случаи, даже только значение (RHS-только) дело.

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