我有一个哈希,其中包含一些数学表达式,它看起来像这样:
my %testhash = ("ABC" => "0.05 + 1 + foo",
"DEF" => "2E+5 -3",
"GHJ" => "2E+5 -3 * bar);
在我的代码中,我想评估每个%testhash
值,但只评估有效值(在此示例中仅"DEF"
foo
和bar
未定义)。
因此,我需要确定哪个keys %testhash
包含[a-zA-Z]
,但指数符号除外。
有没有办法用优雅的单一正则表达式行检查这一点,而无需削减每个值并单独分析?
提前致谢! 亚历
编辑:像新手经常发布一个问题并且没有提供必要的示例数据(对不起),所以我将更新哈希:
my %testhash = ("invalid1" => "0.05 + 1 + foo",
"invalid2" => "2E+5 -3 * bar",
"valid1" => "1.0e-03 + ( 42)",
"valid2" => "((3.0) / 3) * 5",
"valid3" => "2E+5 + 1");
答案 0 :(得分:1)
我没有看到如何在一个语句中处理整个哈希,因为你需要按值过滤但是也要排除密钥。这仅根据要求排除了[a-zA-Z]
。
my %valid_expr;
while ( my ($key, $val) = each %testhash ) {
$valid_expr{$key} = $val if not (
$val =~ / [a-df-z] | e(?!([+-]\d)) /xi or
$val =~ / (?:E[-+]\d)? .* [a-df-z] /xi
);
}
正则表达式:禁止在({可选的)E[+-]\d+
- E后跟+或 - 和数字之前或之后有任何字母的值。中间的.*
允许数字/期间,运营商。
e(?!([+-]\d))
是一个否定前瞻声明:如果没有 e
,则会出现[+-]\d
。
如果您只需要检查正则表达式本身的值
$val !~ /[a-df-z]|(?!([+-]\d))/i and $val !~ /(?:E[-+]\d)?.*[a-df-z]/i
更新将A-Z
添加到原始帖子不允许E
,已更正。已更改为/i
以允许e
。
更新需要向条形e
字符串添加预测,但允许e-02
个指数。
这正确评估了所有示例以及其他一些示例。
然而,它最终收敛到ikegami解决方案。
答案 1 :(得分:1)
如果
,表达式有效因此 [1] ,如果
,表达式无效这给了我们以下内容:
/ [A-DF-Z] | (?<![0-9])E | E(?![+-][0-9]) /ix
记住,
答案 2 :(得分:0)
use strict
所以最好的想法可能是使用正则表达式。顺便说一下,如果你想允许\ n,\ t等等而不仅仅是常规空格,你可以用/ */
替换所有/\s*/
。
如果你想评估,你可能不得不使用某种解析器或eval,它们都可以告诉你你刚读过的数学表达式是否有问题。
例如,你可以这样做:
while (my ($name, $expr) = each %testhash) {
if (defined(my $val = eval($expr))) {
say "$name => $expr => $val"
} else {
print "$name invalide => $@"
}
}
它还允许您检测语法错误(例如,3 + 5 2
不被接受,这可能是个好消息。)
检测错误的另一种方法是检查表达式是否有效的正则表达式,如果不是,则不是:
while (my ($name, $expr) = each %testhash) {
if ($expr !~ m/^ *(\d+(\.\d+)?(E([+-])\d+)?)( *[+*\/-] *(\d+(\.\d+)?(E([+-])\d+)?))* *$/) {
say "$name: invalide expr";
}
}
正则表达式搜索该部分的数字(可能带有小数部分或指数):(\d+(\.\d+)?(E([+-])\d+)?)
。然后它查找一个运算符(*
)后跟一个数字的列表(0或更多,这要归功于[+*\/-]
)。并且允许空间存在。
但是如果你在语法中添加括号,那么它会变得稍微复杂一点,例如你可能需要一个递归的正则表达式。