(PERL) Как отпарсить регулярными выражениями строку

Yevgen
Дата: 07.08.2006 16:02:11
Полцарства за идею! Нужно быстро решить такую проблему. Имею строку:

(disable=0 "Comment 1", enable=1 "Comment 2") "Comment for brackets".

В ней может быть разное количество пробелов как вначале, вконце, так и всередине. Нужно выделить составляющие это строки в отдельные переменные. В скобках может находиться любое количество предопределенных значений, т.к. это перечислимы тип. Т.е. disable и enable - это не постулат. Также комментарии могут присутствовать, а могут отсутствовать. Может быть так:
(var1=0x0 "Comment for var1", var2=0x1 , var3=0x2 "Comment for var3", var4=3) "Comment for brackets"

А регулярными выражениями нужно разбросать таким образом:

1) в переменную $brc = "Comment for brackets" (этого комментария тоже может не быть, тогда $brc = "")

2)в хэш %vars, кде ключи - названия переменных - значения переменных и комментарии к ним:
$vars->{var1}->val = 0x0
$vars->{var1}->comment = "Comment for var1"

$vars->{var2}->val = 0x1
$vars->{var2}->comment = ""

$vars->{var3}->val = 0x2
$vars->{var3}->comment = "Comment for var3"

$vars->{var4}->val = 3
$vars->{var1}->comment = ""

Пожалуйста, подскажите, как это можно наиболее оптимально сделать. Буду рад увидеть любые предложения. Заранее спасибо!
P983579823738492
Дата: 07.08.2006 16:35:09
$string = '(var1=0x0 "Comment for var1", var2=0x1 , var3=0x2 "Comment for var3", var4=3) "Comment for brackets"';

($vars, $comment) = split /\)/, $string ;
$comment =~ s/\s*\"//;
$comment =~ s/\"\s*//;

@var_and_comment = split /\,/, $vars;
foreach $var_and_comment (@var_and_comment ) {
	
	($name,$value) = split /\=/, $var_and_comment;
	$name =~ s/\W//gi;
	$comment{$name} =  $value;
	($value{$name}, @c) = split /\W+/, $value;
	$comment{$name} =~ s/.*\"(.*)\"/\1/;
}

foreach $key (keys %value) {
	print "$key = $value{$key} $comment{$key} $comment \n";
}
Yevgen
Дата: 07.08.2006 17:00:01
P983579823738492
$string = '(var1=0x0 "Comment for var1", var2=0x1 , var3=0x2 "Comment for var3", var4=3) "Comment for brackets"';

($vars, $comment) = split /\)/, $string ;
$comment =~ s/\s*\"//;
$comment =~ s/\"\s*//;

@var_and_comment = split /\,/, $vars;
foreach $var_and_comment (@var_and_comment ) {
	
	($name,$value) = split /\=/, $var_and_comment;
	$name =~ s/\W//gi;
	$comment{$name} =  $value;
	($value{$name}, @c) = split /\W+/, $value;
	$comment{$name} =~ s/.*\"(.*)\"/\1/;
}

foreach $key (keys %value) {
	print "$key = $value{$key} $comment{$key} $comment \n";
}


Спасибо за идею!
P983579823738492
Дата: 07.08.2006 17:17:51
Фигню написал - надо так:

$string = '(var1=0x0 "Comment for var1", var2=0x1 , var3=0x2 "Comment for var3", var4=3) "Comment for brackets"';
$string =~ /\((.*)\)\s*\"(.*)\"/;
$vars    = $1;
$comment = $2;

@var_and_comment = split /\,\s*/, $vars;

foreach $var_and_comment (@var_and_comment ) {
	$var_and_comment =~ /(\w+)\s*=\s*(\w+)/;
	$name = $1; $value{$name} = $2;
	$var_and_comment =~ /(\w+)\s*=\s*(\w+)\s*\"(.*)\"/;
	$comment{$name} = $3;
}

foreach $key (keys %value) {
	print "$key = $value{$key} $comment{$key} \"$comment\" \n";
}
P983579823738492
Дата: 07.08.2006 17:52:48
На самом деле лучше даже вот так:

$string = '(var1=0x0"Comment for var1",var2 =   0x1 ,      var3 =0x2    "Comment for var3",var4=4)"Comment111"';
$string =~ /\((.*)\)/;
$vars    = $1; # Забираем то что в скобках, если там что-то есть/
$string =~ /\((.*)\)\s*\"(.*)\"/;
$comment = $2;  # Забираем то что после скобок, если там ничего нет, прошлая версия скрипта не сработает, она не только не получит $comment но и $vars    прое.ет

@var_and_comment = split /\s*\,\s*/, $vars; # То, что было в скобках раздлеить по запятым, с возможными пробелами впереди и сзади, положить в массив.

foreach $var_and_comment (@var_and_comment ) {
	$var_and_comment =~ /(\w+)\s*=\s*(\w+)/; 
	$name = $1; $value{$name} = $2; # Делим по '=' с возможными пробелами впереди и сзади. Предполагаю, что строка   ..., varN=, .... не допустима. 
	$var_and_comment =~ /(\w+)\s*=\s*(\w+)\s*\"(.*)\"/;
	$comment{$name} = $3; #Забрать коментарий, если есть.
}

foreach $key (keys %value) {
	print "$key = $value{$key}, $comment{$key} | \"$comment\" \n";
}
Yevgen
Дата: 08.08.2006 13:28:24
P983579823738492
На самом деле лучше даже вот так:

$string = '(var1=0x0"Comment for var1",var2 =   0x1 ,      var3 =0x2    "Comment for var3",var4=4)"Comment111"';
$string =~ /\((.*)\)/;
$vars    = $1; # Забираем то что в скобках, если там что-то есть/
$string =~ /\((.*)\)\s*\"(.*)\"/;
$comment = $2;  # Забираем то что после скобок, если там ничего нет, прошлая версия скрипта не сработает, она не только не получит $comment но и $vars    прое.ет

@var_and_comment = split /\s*\,\s*/, $vars; # То, что было в скобках раздлеить по запятым, с возможными пробелами впереди и сзади, положить в массив.

foreach $var_and_comment (@var_and_comment ) {
	$var_and_comment =~ /(\w+)\s*=\s*(\w+)/; 
	$name = $1; $value{$name} = $2; # Делим по '=' с возможными пробелами впереди и сзади. Предполагаю, что строка   ..., varN=, .... не допустима. 
	$var_and_comment =~ /(\w+)\s*=\s*(\w+)\s*\"(.*)\"/;
	$comment{$name} = $3; #Забрать коментарий, если есть.
}

foreach $key (keys %value) {
	print "$key = $value{$key}, $comment{$key} | \"$comment\" \n";
}


Я примерно так и сделал, но появились некоторые ньюансы. Например, в комментариях внутри скобок могут стоять "=", "," или "(", ")". Также, может быть такой вариант записи:

(Const_name_1 "Predefined value, which is used for alert indication", Const_name_2, Const_name_3 "Const_name_3 = 0x0012 (For Win32)") "Comment for brackets".


Я не вижу другого варианта, как собирать по частям строку. Т.е. бить по запятым, а потом итерациями клеить эти куски в соответствующие строки. Мне этот вариант не очень нравится из-за того, что сильно много итераций выйдет на обработку большого числа подобных строк. Плюс ко всему, код и так уже необозрим, а если писать в таком стиле, то это получится вообще "спагетти". Есть ли более оптимальный вариант с использованием регулярных выражений?
Yevgen
Дата: 10.08.2006 14:08:32
Короче, я решил эту проблему таким вот образом. Использовал функции работы со строками. Рабочее на 150%.

sub GetFIFOEnums {
my $self = shift;
my $str = shift; #String to parse
my $enums = shift; #Result structure
my $i;
my $j;
my $nm;
my $val;
my $com;
my @a;

my $state = 0; #0 Without "=", ",", "\".
#1 "="
#2 "\""
#3 "\"\""

$j = "";

undef(%{$enums});
#print $str."\n";

while($str ne "")
{
$i = substr($str, 0, 1);
substr($str, 0, 1) = "";
#print "!!".$i."!!".$str."\n";
SWITCH: {
if($i eq "=") {
$state = 1;
$nm = $j;
$j = "";
last SWITCH;
}
if($i eq "\"") {
if($state == 0) {
$state = 2;
$nm = $j;
$val = "";
$j = "";
last SWITCH;
}
if($state == 1) {
$state = 2;
$val = $j;
$j = "";
last SWITCH;
}
if($state == 2) {
$state = 3;
$com = $j;
#print "Nm = ".$nm." Val = ".$val." Com = ".$com."\n";
$j = "";
last SWITCH;
}
}
if($i eq ",") {
if($state == 0) {
$nm = $j;
$val = "";
$com = "";
#print "Nm = ".$nm." Val = ".$val." Com = ".$com."\n";
$enums->{$nm} = undef;
$enums->{$nm}->{val} = $val;
$enums->{$nm}->{comment} = $com;
$j = "";
last SWITCH;
}
if($state == 1) {
$val = $j;
$com = "";
#print "Nm = ".$nm." Val = ".$val." Com = ".$com."\n";
$enums->{$nm} = undef;
$enums->{$nm}->{val} = $val;
$enums->{$nm}->{comment} = $com;
$j = "";
last SWITCH;
}
if($state == 2) {
$j .= $i;
last SWITCH;
}
if($state == 3) {
$state = 0;
$enums->{$nm} = undef;
$enums->{$nm}->{val} = $val;
$enums->{$nm}->{comment} = $com;
last SWITCH;
}
last SWITCH;
}
$j .= $i;
}
#print $i;
}
if($j ne "" && $state == 0)
{
$nm = $j;
$val = "";
$com = "";
$j = "";
#print "Nm = ".$nm." Val = ".$val." Com = ".$com."\n";
$enums->{$nm} = undef;
$enums->{$nm}->{val} = $val;
$enums->{$nm}->{comment} = $com;
}
if($state == 1)
{
$enums->{$nm} = undef;
$enums->{$nm}->{val} = $j;
$enums->{$nm}->{comment} = $com;
}
if($state == 3)
{
#print "Nm = ".$nm." Val = ".$val." Com = ".$com."\n";
$enums->{$nm} = undef;
$enums->{$nm}->{val} = $val;
$enums->{$nm}->{comment} = $com;
}
#@a = keys %{$enums};
#foreach $i(@a)
#{
# print "Nm = ".$i." Val = ".$enums->{$i}->{val}." Com = ".$enums->{$i}->{comment}."\n";
#}
#exit 0;
}