kzen.dev
  • Вопросы
  • Метки
  • Пользователи
Оповещения
Вознаграждения
Регистрация
После регистрации, сможете получать уведомления об ответах и комментариях на Ваши вопросы.
Вход
Если у Вас уже есть аккаунт, войдите чтобы проверить новые уведомления.
Тут будут вознаграждения за добавленные вопросы, ответы и комментарий.
Дополнительно
Источник
Редактировать
Derek Park
Derek Park
Вопрос

Разбор атрибутов с помощью regex в Perl

Вот с какой проблемой я недавно столкнулся. У меня есть строки атрибутов вида

"x=1 and y=abc and z=c4g and ..."

Некоторые атрибуты имеют числовые значения, некоторые - альфа-значения, некоторые - смешанные, некоторые - даты и т.д.

Каждая строка полагается иметь "x=someval и y=anotherval" в начале, но некоторые не имеют этого. Мне нужно сделать три вещи.

  1. Проверить строки на предмет наличия в них x и y.
  2. Проанализируйте значения x и y.
  3. Получить остальную часть строки.

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

$x = 1;
$y = "abc";
$remainder = "z=c4g and ..."

Мой вопрос: есть ли (достаточно) простой способ разобрать эти переменные и проверить их с помощью одного регулярного выражения? Т.е:

if ($str =~ /someexpression/)
{
    $x = $1;
    $y = $2;
    $remainder = $3;
}

Обратите внимание, что строка может состоять только из атрибутов x и y. Это допустимая строка.

Я опубликую свое решение в качестве ответа, но оно не соответствует моим предпочтениям в отношении единственного регекса.

2 2008-08-14T00:40:26+00:00 5
Программирование
regex
perl
Brad Gilbert
Brad Gilbert
21-го августа 2008 в 8:02
2008-08-21T20:02:11+00:00
Дополнительно
Источник
Редактировать
#8414466

Принятие Вас также хочет сделать что-то с другими name=value парами, которые это - то, как я сделал бы это (использование версии 5.10 Perl):

use 5.10.0;
use strict;
use warnings;

my %hash;
while(
    $string =~ m{
       (?: ^ | \G )    # start of string or previous match
       \s*

       (?<key>   \w+ ) # word characters
       =
       (?<value> \S+ ) # non spaces

       \s*             # get to the start of the next match
       (?: and )?
    }xgi
){
    $hash{$+{key}} = $+{value};
}

# to make sure that x & y exist
die unless exists $hash{x} and exists $hash{y};

На более старом Perls (по крайней мере, Perl 5.6);

use strict;
use warnings;

my %hash;
while(
    $string =~ m{
       (?: ^ | \G )   # start of string or previous match
       \s*

       ( \w+ ) = ( \S+ )

       \s*            # get to the start of the next match
       (?: and )?
    }xgi
){
    $hash{$1} = $2;
}

# to make sure that x & y exist
die unless exists $hash{x} and exists $hash{y};

Они обладают дополнительным преимуществом продолжения работать, если Вы должны работать с большим количеством данных.

Brad Gilbert
Brad Gilbert
Редактировал ответ 15-го июля 2009 в 4:37
3
0
Решение / Ответ
Rudd Zwolinski
Rudd Zwolinski
14-го августа 2008 в 1:56
2008-08-14T01:56:53+00:00
Дополнительно
Источник
Редактировать
#8414464

Я не очень хорошо разбираюсь в регулярных выражениях, но, похоже, это довольно близко к тому, что вы ищете:

/x=(.+) and y=([^ ]+)( and (.*))?/

За исключением того, что вы используете $1, $2 и $4. Используется:

my @strs = ("x=1 and y=abc and z=c4g and w=v4l",
            "x=yes and y=no",
            "z=nox and w=noy");

foreach (@strs) {
    if ($_ =~ /x=(.+) and y=([^ ]+)( and (.*))?/) {
        $x = $1;
        $y = $2;
        $remainder = $4;
        print "x: $x; y: $y; remainder: $remainder\n";
    } else {
        print "Failed.\n";
    }
}

Вывод:

x: 1; y: abc; remainder: z=c4g and w=v4l
x: yes; y: no; remainder: 
Failed.

Это, конечно, оставляет много проверки ошибок, и я не знаю всего о ваших входных данных, но это, кажется, работает.

1
0
 Cebjyre
Cebjyre
17-го августа 2008 в 3:39
2008-08-17T15:39:50+00:00
Дополнительно
Источник
Редактировать
#8414465

В качестве довольно простой модификации к версии Радда,

/^x=(.+) and y=([^ ]+)(?: and (.*))?/

позволит вам использовать $1, $2 и $3 (символ ?: делает его не захватывающей группой), и будет гарантировать, что строка начинается с "x=", вместо того, чтобы позволить "not_x=" соответствовать

Если вы лучше знаете, какими будут значения x и y, это следует использовать для дальнейшего ужесточения regex:

my @strs = ("x=1 and y=abc and z=c4g and w=v4l",
        "x=yes and y=no",
        "z=nox and w=noy",
        "not-x=nox and y=present",
        "x=yes and w='there is no and y=something arg here'");

foreach (@strs) {
    if ($_ =~ /^x=(.+) and y=([^ ]+)(?: and (.*))?/) {
        $x = $1;
        $y = $2;
        $remainder = $3;
        print "x: {$x}; y: {$y}; remainder: {$remainder}\n";
    } else {
        print "$_ Failed.\n";
    }
}

Выход:

x: {1}; y: {abc}; remainder: {z=c4g and w=v4l}
x: {yes}; y: {no}; remainder: {}
z=nox and w=noy Failed.
not-x=nox and y=present Failed.
x: {yes and w='there is no}; y: {something}; remainder: {}

Обратите внимание, что отсутствие части последнего теста связано с тем, что текущая версия теста y не требует пробелов, если бы тест x имел такое же ограничение, эта строка не прошла бы.

1
0
 Frosty
Frosty
15-го сентября 2008 в 3:20
2008-09-15T15:20:12+00:00
Дополнительно
Источник
Редактировать
#8414467

Rudd и Cebjyre получили Вас большая часть пути там, но у них обоих есть определенные проблемы:

Красноперка предложила:

/x = (. +) и y = ([^] +) (и (.*))? /

Cebjyre изменил его к:

/^x = (. +) и y = ([^] +) (?: и (.*))? /

Вторая версия лучше, потому что она не перепутает " not_x=foo" с " x=foo" но примет вещи, такие как " x=foo z=bar y=baz" и набор 1$ = " foo z=bar" который является нежелательным.

Это, вероятно, что Вы ищете:

/^x = (\w +) и y = (\w +) (?: и (.*))? /

Это отвергает что-либо между x = и y = варианты, помещает и позволяет и дополнительный " и..." который будет в 3$

1
0
Derek Park
Derek Park
14-го августа 2008 в 12:46
2008-08-14T00:46:38+00:00
Дополнительно
Источник
Редактировать
#8414463

Вот, в принципе, что я сделал, чтобы решить эту проблему:

($x_str, $y_str, $remainder) = split(/ and /, $str, 3);

if ($x_str !~ /x=(.*)/)
{
    # error
}

$x = $1;

if ($y_str !~ /y=(.*)/)
{
    # error
}

$y = $1;

Я'опустил некоторую дополнительную валидацию и обработку ошибок. Эта техника работает, но она не такая лаконичная и красивая, как мне бы хотелось. Я надеюсь, что кто-нибудь предложит мне лучший вариант.

0
0
Похожие сообщества 3
Regular Expressions
Regular Expressions
1 044 пользователей
Chat about the Regular Expressions. Please use https://regexr.com https://regex101.com for share your regexes. For practice use: https://regexcrossword.com https://regexone.com
Открыть telegram
Modern::Perl
Modern::Perl
460 пользователей
Пожалуйста, представьтесь при добавлении в группу. Это необходимо во избежание спам-ботов. Ваше первое сообщение не должно быть ссылкой или репостом. Мы всегда рады нестандартным вопросам.
Открыть telegram
use Perl or die;
use Perl or die;
299 пользователей
Группа о языке Perl и обо всём что с ним связано.
Открыть telegram
Добавить вопрос
Категории
Все
Технологий
Культура / Отдых
Жизнь / Искусство
Наука
Профессии
Бизнес
Пользователи
Все
Новые
Популярные
1
Ilya Smirnov
Зарегистрирован 6 дней назад
2
Денис Васьков
Зарегистрирован 1 неделю назад
3
Dima Patrushev
Зарегистрирован 1 неделю назад
4
sirojidddin otaboyev
Зарегистрирован 2 недели назад
5
Елена Гайдамамакинат
Зарегистрирован 2 недели назад
ID
KO
RU
© kzen.dev 2023
Источник
stackoverflow.com
под лицензией cc by-sa 3.0 с атрибуцией