使用正则表达式从此字符串获取字符串模式
我有一个字符串,如下所示在我的C#应用程序中。使用正则表达式从此字符串获取字符串模式
Multiply(Sum(3,5,4), Division(4,5,5), Subtract(7,8,9))
Sum()
,Division()
,Subtract()
是Multiple()
内的不同的不同方法。
有没有什么办法像Sum(3,5,4)
,Division(4,5,5)
,Substract(7,8,9)
和Multiply()
使用C#Regex方法分别得到每一个?
Sum
,Division
,Substract
和Multiply
是常数关键字。
是的,如果你没有使用另一个方法调用时,将参数传递给你的方法。
(如Sum(2, Sum(3,2), 4)
)
在你可以使用这个模式的话:^\w+\((.*)\)$
再拿到1组(它是(*)组。)这是参数(Sum(3,5,4), Division(4,5,5), Subtract(7,8,9)
),然后使用这个模式来getted组找到的所有参数:\w+\(.*\)
如果您的乘方法可能有另一个嵌套方法,正则表达式不能帮助you.In这种情况下,你应该算括号,看看哪些wher关闭
如果嵌套任意深度,你应该这样做迭代地使用Regexp.Matches()
和Regexp.Replace()
。
复制整个字符串。使用([a-zA-Z]+\([0-9, ]*\))(,)?
作为正则表达式。这将匹配所有最底层的函数调用 - 调用图的所有叶节点。
致电Regexp.Matches
提取所有的匹配,请拨打Regexp.Replace
摆脱他们所有的字符串副本。这将摆脱调用图的所有叶节点。再次呼叫Matches()
和Replace()
以摆脱下一级调用,并继续重复,直到字符串副本为空。
用'\ W启动+ \((\ d,?)+ \)',并在字符串通过,取代基于什么在你身边走过算出答案发现每场比赛,你会不停地重复这一点,直到最后一件事留在字符串中是答案。 – 2012-01-09 14:40:22
您无法使用RegExp进行任意嵌套 - 由于RegExp模型的限制,即使理论上也不可能是。
你在这种情况下需要的是一个解析器。它不需要太多的工作来手动构建一个非常简单的recursive descent parser,但是一旦复杂性变得相当大,您应该切换到解析器生成器。我个人最喜欢的是ANTLR,但你有很多其他的选择。
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