C#應該能夠通過正則表達式中的遞歸來實現平衡文本。唯一的問題是我認爲它保留了整個外部比賽。爲了進一步解析內部內容(在括號之間),需要遞歸函數調用,每次都選取令牌。
我同意@dasblinkenlight,但需要一個體面的解析器。正如他所說,複雜性可能迅速變得相當可觀。
下面的正則表達式來自Perl,但構造對於.Net黑客應該是相同的。
正如你所看到的,正則表達式就像是在一般形式粘附於鈦硅分子篩,但
只有逗號和數字是數學標記之間進行處理,使其餘告吹。
但是,如果這是你所關心的唯一的事情,那麼它應該工作。您會注意到即使您可以將它解析爲數據結構(如下所示),但要以內部方式使用該結構,還需要在數據結構上進行另一個遞歸「解析」(儘管比較容易)。如果出於顯示或統計目的,那麼它不是問題。
擴展的正則表達式:
{
( #1 - Recursion group 1
\b(\w+)\s* #2 - Math token
\( # - Open parenth
( #3 - Capture between parenth's
(?: (?> (?: (?!\b\w+\s*\(|\)) .)+) # - Get all up to next math token or close parenth
| (?1) # - OR, recurse group 1
)* # - Optionally do many times
) # - End capture 3
\) # - Close parenth
) # - End recursion group 1
\s*(\,?) #4 - Capture optional comma ','
| # OR,
# (Here, it is only getting comma and digits, ignoring the rest.
# Comma's ',' are escaped to make them standout)
\s*
(?| # - Start branch reset
(\d+)\s*(\,?) #5,6 - Digits then optional comma ','
| (?<=\,)()\s*(\,|\s*$) #5,6 - Comma behind. No digit then, comma or end
) # - End branch reset
}xs; # Options: expanded, single-line
這裏是一個快速原型在Perl(更容易比C#):
use Data::Dumper;
#//
my $regex = qr{(\b(\w+)\s*\(((?:(?>(?:(?!\b\w+\s*\(|\)).)+)|(?1))*)\))\s*(\,?)|\s*(?|(\d+)\s*(\,?)|(?<=\,)()\s*(\,|\s*$))}s;
#//
my $sample = ', asdf Multiply(9, 4, 3, hello, _Sum(3,5,4,) , Division(4, Sum(3,5,4), 5), ,, Subtract(7,8,9))';
print_math_toks(0, $sample);
my @array;
store_math_toks(0, $sample, \@array);
print Dumper(\@array);
#//
sub print_math_toks
{
my ($cnt, $segment) = @_;
while ($segment =~ /$regex/g)
{
if (defined $5) {
next if $cnt < 1;
print "\t"x($cnt+1), "$5$6\n";
}
else {
++$cnt;
print "\t"x$cnt, "$2(\n";
my $post = $4;
$cnt = print_math_toks($cnt, $3);
print "\t"x$cnt, ")$post\n";
--$cnt;
}
}
return $cnt;
}
sub store_math_toks
{
my ($cnt, $segment, $ary) = @_;
while ($segment =~ /$regex/g)
{
if (defined $5) {
next if $cnt < 1;
if (length $5) {
push (@$ary, $5);
}
else {
push (@$ary, '');
}
}
else {
++$cnt;
my %hash;
$hash{$2} = [];
push (@$ary, \%hash);
$cnt = store_math_toks($cnt, $3, $hash{$2});
--$cnt;
}
}
return $cnt;
}
輸出:
Multiply(
9,
4,
3,
_Sum(
3,
5,
4,
),
Division(
4,
Sum(
3,
5,
4
),
5
),
,
,
Subtract(
7,
8,
9
)
)
$VAR1 = [
{
'Multiply' => [
'9',
'4',
'3',
{
'_Sum' => [
'3',
'5',
'4',
''
]
},
{
'Division' => [
'4',
{
'Sum' => [
'3',
'5',
'4'
]
},
'5'
]
},
'',
'',
{
'Subtract' => [
'7',
'8',
'9'
]
}
]
}
];
你打算窩他們進一步?說,乘以(乘(乘(1,2),乘(3,4)),乘(5,6))?還需要嵌套的 – dasblinkenlight 2012-01-09 14:00:30
。那可能嗎 ? – user904567 2012-01-09 14:28:58
我的解決方案如下處理嵌套。因爲需要嵌套,所以你不能用一個簡單的Regex方法調用它,你必須使用for循環。這不應該是一個大問題。 – 2012-01-09 15:40:34