我认为 Regex 不能用于检测丢失的括号是否正确(因为无法计算对)?使用 JavaScript,我已经截断了大约一千个字符串,需要手动编辑。我希望能够使用代码将这个列表缩小到需要注意的那些。字符串可以被认为是以下形式:
- (这很好,不需要注意)
- 这也[好]
- 这很糟糕(需要编辑
- 这[(也)不好
- 就像这}不好
- 这个字符串没有任何类型的括号,但也必须考虑
如果这不可能,那么我只需要编写一个函数来查找括号对。谢谢
我认为 Regex 不能用于检测丢失的括号是否正确(因为无法计算对)?使用 JavaScript,我已经截断了大约一千个字符串,需要手动编辑。我希望能够使用代码将这个列表缩小到需要注意的那些。字符串可以被认为是以下形式:
如果这不可能,那么我只需要编写一个函数来查找括号对。谢谢
function isFine(str) {
return /[(){}\[\]]/.test( str ) &&
( str.match( /\(/g ) || '' ).length == ( str.match( /\)/g ) || '' ).length &&
( str.match( /\[/g ) || '' ).length == ( str.match( /]/g ) || '' ).length &&
( str.match( /{/g ) || '' ).length == ( str.match( /}/g ) || '' ).length;
}
测试
isFine('(this is fine and does not need attention)'); // true
isFine('This is also [fine]'); // true
isFine('This is bad( and needs to be edited'); // false
isFine('This [is (also) bad'); // false
isFine('as is this} bad'); // false
isFine('this string has no brackets but must also be considered'); // false
但请注意,这不会检查括号顺序,即被a)b(c
视为没问题。
为了记录,这里有一个函数检查丢失的括号并检查每种类型是否正确平衡。它不允许a)b(c
,但它确实允许(a[bc)d]
,因为每种类型都是单独检查的。
function checkBrackets( str ) {
var lb, rb, li, ri,
i = 0,
brkts = [ '(', ')', '{', '}', '[', ']' ];
while ( lb = brkts[ i++ ], rb = brkts[ i++ ] ) {
li = ri = 0;
while ( li = str.indexOf( lb, li ) + 1 ) {
if ( ( ri = str.indexOf( rb, ri ) + 1 ) < li ) {
return false;
}
}
if ( str.indexOf( rb, ri ) + 1 ) {
return false;
}
}
return true;
}
最后,在 Christophe 的帖子之后,这似乎是检查缺少括号并检查所有括号是否正确平衡和嵌套的最佳解决方案:
function checkBrackets( str ) {
var s;
str = str.replace( /[^{}[\]()]/g, '' );
while ( s != str ) {
s = str;
str = str.replace( /{}|\[]|\(\)/g, '' )
}
return !str;
};
checkBrackets( 'ab)cd(efg' ); // false
checkBrackets( '((a)[{{b}}]c)' ); // true
checkBrackets( 'ab[cd]efg' ); // true
checkBrackets( 'a(b[c)d]e' ); // false
您不能在正则表达式本身中进行递归,但您始终可以在 JavaScript 中进行。
这是一个例子:
// First remove non-brackets:
string=string.replace(/[^{}[\]()]/g,"");
// Then remove bracket pairs recursively
while (string!==oldstring) {
oldstring=string;
string=string.replace(/({}|\[\]|\(\))/g,"");
}
其余的是不匹配的括号。
现场演示:http: //jsfiddle.net/3Njzv/
如果您需要计算配对,您可以一次更换一个并添加一个计数器:
// First remove non-brackets:
string=string.replace(/[^{}[\]()]/g,"");
// Then remove bracket pairs recursively
var counter=-1;
while (string!==oldstring) {
counter ++;
oldstring=string;
string=string.replace(/({}|\[\]|\(\))/,"");
}
可以使用递归正则表达式来验证匹配的括号。例如,在 Perl 中,以下表达式匹配正确()
{}
[]
嵌套的字符串:
$r = qr/(?:(?>[^(){}\[\]]+)|\((??{$r})\)|\{(??{$r})\}|\[(??{$r})\])*/;
为了清楚起见,扩展了相同的表达式:
$r = qr/
(?:
(?>
[^(){}\[\]]+
)
|
\(
(??{$r})
\)
|
\{
(??{$r})
\}
|
\[
(??{$r})
\]
)*
/x;
外部组被量化*
而不是+
匹配空字符串,因此为了$r
有用,实际匹配必须使用利用前瞻/后视或以其他方式建立上下文的表达式来完成,例如/^$r$/
. 例如,以下仅打印文件中没有正确嵌套的行:
perl -ne '$r = qr/(?:(?>[^(){}\[\]]+)|\((??{$r})\)|\{(??{$r})\}|\[(??{$r})\])*/; print if !m/^$r$/' file
为了澄清您的问题:如果这些是文件名而不是文件内容,您可以将ls
orfind
或其他任何内容的输出通过管道传输到上述命令 sans 中file
:
ls | perl -ne '$r = qr/(?:(?>[^(){}\[\]]+)|\((??{$r})\)|\{(??{$r})\}|\[(??{$r})\])*/; print if !m/^$r$/'
但是,正如其他人所说,一般来说,非正则表达式解决方案可能更好。
注意来自Perl 文档:“警告:这个扩展的正则表达式功能被认为是实验性的,可能会在没有通知的情况下进行更改。由于正则表达式引擎中未来优化的影响,执行的具有副作用的代码在不同版本之间的执行可能不同。”
一些正则表达式风格能够匹配嵌套括号等递归结构,但语法非常复杂,通常只写一个函数就更容易了。JavaScript 正则表达式根本不支持递归。