正则表达式 - 懒惰和非捕获

时间:2011-12-23 12:06:18

标签: sql regex oracle scripting vbscript

要搜索的字符串:

VALUES ('9gfdg', to_date('1876/12/06','YYYY/MM/DD'), null) 

到目前为止正则表达式搜索:

VALUES\s*\(\s*'?\s*(.+?)\s*'?\s*,\s*'?\s*(.+?)\s*'?\s*,\s*'?\s*(.+?)\s*'?\s*\)

正则表达式替换为3组:即\1 \2 \3

我的目标是:

9gfdg to_date('1876/12/06' ,'YYYY/MM/DD')  null

但是得到(因为to_Date中的额外逗号而且懒惰而不是贪婪):

9gfdg to_date('1876/12/06 YYYY/MM/DD , null) 

注意: 它正好是3个字段(3个字段中的值可能不同,但您可以了解我正在努力解决的格式)。即每个字段都可以有逗号(通常是字符值,可以是关键字,如null,可以是数字,也可以是to_Date表达式。

正则表达式引擎是VBA / VBscript

任何人都有关于修复此正则表达式的任何指示?

3 个答案:

答案 0 :(得分:1)

如果只有第二个参数可以包含逗号,您可以执行以下操作:

^VALUES\s*\(\s*'?([^',]*)'?\s*,\s*(.*?)\s*,\s*'?([^',]*)'?\s*\)$

否则我不知道正则表达式支持哪些功能,所以很难让一些更有趣的东西。如果不支持(?R),你总是可以制作有限深度的嵌套括号正则表达式。

答案 1 :(得分:1)

对于更一般的情况,您可以尝试以下方式:

^\s*
VALUES\s*
\(
\s*
(?: '([^']*)' | ( \w+ (?: \( [^()]* \) )? ) )
\s*,\s*
(?: '([^']*)' | ( \w+ (?: \( [^()]* \) )? ) )
\s*,\s*
(?: '([^']*)' | ( \w+ (?: \( [^()]* \) )? ) )
\s*
\)\s*
$

删除了空格:

^\s*VALUES\s*\(\s*(?:'([^']*)'|(\w+(?:\([^()]*\))?))\s*,\s*(?:'([^']*)'|(\w+(?:\([^()]*\))?))\s*,\s*(?:'([^']*)'|(\w+(?:\([^()]*\))?))\s*\)\s*$

替换为:

\1\2 \3\4 \5\6

应该适用于一个嵌套的括号级别,而不带任何带括号的括号。

PS:未经测试。如果你的味道支持/x标志,你通常可以使用间隔正则表达式。

答案 2 :(得分:1)

这是一个解决方案。

请注意$field的正则表达式:它是normal* (special normal*)*模式的另一个应用程序,normal只是逗号([^,])和{{1}一个逗号,只要它后面没有两个单引号(special)。但是,使用,(?!'')代替normal,第一个+非空。

perl中的演示代码。 perl中的字符串连接运算符是一个点:

*

演示输出:

fge@erwin $ cat t.pl
#!/usr/bin/perl -W
use strict;

# Value separator: a comma optionally surrounded by spaces
my $value_separator = '\s*,\s*';

# Literal "null", and a number
my $null = 'null';
my $number = '\d+';

# Text field
my $normal = '[^,]'; # Anything but a comma
my $special = ",(?!'')"; # A comma, _not_ followed by two single quotes
my $field = "'$normal+(?:$special$normal*)*'"; # a text field

# A to_date() expression
my $to_date  = 'to_date\(\s*' . $field . $value_separator . $field . '\s*\)';

# Any field
my $any_field = '(' . $null . '|' . $number . '|' . $field . '|' . $to_date . ')';

# The full regex
my $full_regex = '^\s*VALUES\s*\(\s*' . $any_field . $value_separator . $any_field
    . $value_separator . $any_field . '\s*\)\s*$';

# This builds a compiled form of the regex
my $re = qr/$full_regex/;

# Read from stdin, try and match (m//), if match, print the three captured groups
while (<STDIN>) {
        m/$re/ and print <<EOF;
Argument 1: -->$1<--
Argument 2: -->$2<--
Argument 3: -->$3<--
EOF
}

有一点需要注意:你会注意到我没有使用任何懒惰的量词,甚至连点都没用!

编辑:字段中的fge@erwin ~ $ perl t.pl VALUES ('9gfdg', to_date('1876/12/06','YYYY/MM/DD'), null) Argument 1: -->'9gfdg'<-- Argument 2: -->to_date('1876/12/06','YYYY/MM/DD')<-- Argument 3: -->null<-- VALUES('prout', 'ma', 'chere') Argument 1: -->'prout'<-- Argument 2: -->'ma'<-- Argument 3: -->'chere'<-- VALUES(324, 'Aiie, a comma', to_date('whatever', 'is there, even commas')) Argument 1: -->324<-- Argument 2: -->'Aiie, a comma'<-- Argument 3: -->to_date('whatever', 'is there, even commas')<-- 实际上是一个逗号后面没有两个单引号,而不是一个