我想在数学表达式中找到未包含在{
和}
示例:
输入:abc+1*def
匹配:["abc", "1", "def"]
输入:{abc}+1+def
匹配:["1", "def"]
输入:abc+(1+def)
匹配:["abc", "1", "def"]
输入:abc+(1+{def})
匹配:["abc", "1"]
输入:abc def+(1.1+{ghi})
匹配:["abc def", "1.1"]
输入:1.1-{abc def}
匹配:["1.1"]
规则
{
的情况下开始}
,则不能开始括号+
-
/
*
和(
)
{
}
(无嵌套括号)到目前为止,我的结尾是:http://regex101.com/r/gU0dO4
(^[^/*+({})-]+|(?:[/*+({})-])[^/*+({})-]+(?:[/*+({})-])|[^/*+({})-]+$)
我将任务分成3:
但它没有按预期工作。
有什么想法吗?
答案 0 :(得分:3)
对于标准正则表达式匹配{}
,特别是嵌套的很难(读不可能),因为它需要计算您遇到的{
的数量,因此您知道哪个}
终止了它。
相反,一个简单的字符串操作方法可以工作,这是一个非常基本的解析器,它只是从左到右读取字符串,并在括号外使用它。
var input = "abc def+(1.1+{ghi})"; // I assume well formed, as well as no precedence
var inParens = false;
var output = [], buffer = "", parenCount = 0;
for(var i = 0; i < input.length; i++){
if(!inParens){
if(input[i] === "{"){
inParens = true;
parenCount++;
} else if (["+","-","(",")","/","*"].some(function(x){
return x === input[i];
})){ // got symbol
if(buffer!==""){ // buffer has stuff to add to input
output.push(buffer); // add the last symbol
buffer = "";
}
} else { // letter or number
buffer += input[i]; // push to buffer
}
} else { // inParens is true
if(input[i] === "{") parenCount++;
if(input[i] === "}") parenCount--;
if(parenCount === 0) inParens = false; // consume again
}
}
答案 1 :(得分:1)
这可能是一个有趣的正则表达式挑战,但在现实世界中,只需查找所有[^+/*()-]+
组并删除{}
"abc def+(1.1+{ghi})".match(/[^+/*()-]+/g).filter(
function(x) { return !/^{.+?}$/.test(x) })
// ["abc def", "1.1"]
话虽这么说,正则表达式不是解析数学表达式的正确方法。对于严格的解析,请考虑使用正式的语法和解析器。有很多用于javascript的解析器生成器,例如,在PEG.js中你可以写一个像
这样的语法expr
= left:multiplicative "+" expr
/ multiplicative
multiplicative
= left:primary "*" right:multiplicative
/ primary
primary
= atom
/ "{" expr "}"
/ "(" expr ")"
atom = number / word
number = n:[0-9.]+ { return parseFloat(n.join("")) }
word = w:[a-zA-Z ]+ { return w.join("") }
并生成一个能够转向的解析器
abc def+(1.1+{ghi})
到
[
"abc def",
"+",
[
"(",
[
1.1,
"+",
[
"{",
"ghi",
"}"
]
],
")"
]
]
然后你可以正常迭代这个数组并获取你感兴趣的部分。
答案 2 :(得分:1)
您提到的变量名称可以与\b[\w.]+\b
匹配,因为它们受到字词分隔符的严格限制
由于您有完善的公式,您不想捕获的名称后面都是}
,因此您可以使用超前表达式来排除这些:
(\b[\w.]+ \b)(?!})
将匹配所需的元素(http://regexr.com/38rch)。
修改强>
对于正确匹配等更复杂的用途:
我们需要将超前期限更改为(?|({|}))
要包含1.2-{abc def}
的匹配项,我们需要更改\b
1 。这个术语使用的是javascript中没有的外观表达式。所以我们必须解决。
(?:^|[^a-zA-Z0-9. ])([a-zA-Z0-9. ]+(?=[^0-9A-Za-z. ]))(?!({|}))
对于我们的示例(http://regex101.com/r/oH7dO1)似乎是一个很好的例子。
1 \b
是\w
和\W
\z
或\a
之间的分隔。由于\w
不包含空格而\W
不包含空格,因此它与变量名的定义不兼容。
答案 3 :(得分:0)
继续使用user2864740的评论,您可以将{}
之间的所有内容替换为空,然后匹配其余内容。
var matches = "string here".replace(/{.+?}/g,"").match(/\b[\w. ]+\b/g);
由于您知道表达式有效,只需选择\w+