仅当不在引号字段中或在 2 个引号之间时才匹配字符
Match a character only when not in a quoted field or in between 2 quotes
考虑以下字符串:
"bla ; bla"; bla
"bla "";"" bla"; bla
"bla ";" bla"; bla
我正在尝试匹配任何不在引号字段(例如 "bla ; bla"
)或两个引号之间的 ;
。
换句话说,我想匹配前两个字符串中的第二个 ;
和最后一个字符串中的所有 ;
。
这是我一直在尝试的 2 个正则表达式,但我无法制作出适用于所有情况的正则表达式。
^(['"])(?:(?!).)*(?=;)(*SKIP)(*F)|;
^(['"])(?:(?!(?!)).)*(?=;)(*SKIP)(*F)|;
有什么想法吗?
编辑
我在最初的问题中省略了几个重要的细节。上面的示例行来自 .csv
个文件。我正在尝试从不同的文件中提取所有文件分隔符 ;
。我遇到的问题是区分带引号的字段(第 2 行)中带引号的 ;
和由 ;
分隔的两个带引号的字段(第 3 行)。在我的例子中,引用的字段后面总是跟着 ;
。
你可以使用
(?:"[^"]*(?:""[^"]*)*"|'[^']*(?:''[^']*)*')(?<!;["'])(*SKIP)(*F)|;
参见regex demo。 详情:
(?:"[^"]*(?:""[^"]*)*"|'[^']*(?:''[^']*)*')
- 非捕获组匹配
"[^"]*(?:""[^"]*)*"
- "
,然后是 "
字符以外的任何零个或多个字符,然后是 ""
字符串的零个或多个出现,然后是任何"
字符以外的零个或多个字符,然后又是 "
|
- 或
'[^']*(?:''[^']*)*'
- '
,然后是 '
字符以外的任何零个或多个字符,然后是 ''
字符串的零个或多个出现,然后是任何'
字符以外的零个或多个字符,然后又是 '
(?<!;["'])
- 如果 ;
和 '
或 "
紧邻当前位置[=49= 的左侧,则匹配失败的负后视]
(*SKIP)(*F)
- 匹配失败并从失败位置开始搜索下一个匹配
|
- 或
;
- 一个分号。
最简单(AFAIK 最短)和广泛支持(不使用 SKIP
,通常不支持):
(?<!"");(?!"")(?=((?:[^"]*"){2})*[^"]*$)
参见live demo。
它通过使用环视断言来工作:
- 没有用双引号引起来
- 后跟偶数个(包括零个)引号
使用像 Text::CSV_XS
这样的实际 CSV 解析器(好吧,Semicolon-SV),而不是试图用正则表达式破解某些东西:
#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
use Text::CSV_XS;
my $csv = Text::CSV_XS->new({ binary => 1, sep_char => ";"});
while (my $row = $csv->getline(\*DATA)) {
say $row->[0];
}
__DATA__
"bla ; bla"; bla
"bla "";"" bla"; bla
"bla ";" bla"; bla
考虑以下字符串:
"bla ; bla"; bla
"bla "";"" bla"; bla
"bla ";" bla"; bla
我正在尝试匹配任何不在引号字段(例如 "bla ; bla"
)或两个引号之间的 ;
。
换句话说,我想匹配前两个字符串中的第二个 ;
和最后一个字符串中的所有 ;
。
这是我一直在尝试的 2 个正则表达式,但我无法制作出适用于所有情况的正则表达式。
^(['"])(?:(?!).)*(?=;)(*SKIP)(*F)|;
^(['"])(?:(?!(?!)).)*(?=;)(*SKIP)(*F)|;
有什么想法吗?
编辑
我在最初的问题中省略了几个重要的细节。上面的示例行来自 .csv
个文件。我正在尝试从不同的文件中提取所有文件分隔符 ;
。我遇到的问题是区分带引号的字段(第 2 行)中带引号的 ;
和由 ;
分隔的两个带引号的字段(第 3 行)。在我的例子中,引用的字段后面总是跟着 ;
。
你可以使用
(?:"[^"]*(?:""[^"]*)*"|'[^']*(?:''[^']*)*')(?<!;["'])(*SKIP)(*F)|;
参见regex demo。 详情:
(?:"[^"]*(?:""[^"]*)*"|'[^']*(?:''[^']*)*')
- 非捕获组匹配"[^"]*(?:""[^"]*)*"
-"
,然后是"
字符以外的任何零个或多个字符,然后是""
字符串的零个或多个出现,然后是任何"
字符以外的零个或多个字符,然后又是"
|
- 或'[^']*(?:''[^']*)*'
-'
,然后是'
字符以外的任何零个或多个字符,然后是''
字符串的零个或多个出现,然后是任何'
字符以外的零个或多个字符,然后又是'
(?<!;["'])
- 如果;
和'
或"
紧邻当前位置[=49= 的左侧,则匹配失败的负后视](*SKIP)(*F)
- 匹配失败并从失败位置开始搜索下一个匹配|
- 或;
- 一个分号。
最简单(AFAIK 最短)和广泛支持(不使用 SKIP
,通常不支持):
(?<!"");(?!"")(?=((?:[^"]*"){2})*[^"]*$)
参见live demo。
它通过使用环视断言来工作:
- 没有用双引号引起来
- 后跟偶数个(包括零个)引号
使用像 Text::CSV_XS
这样的实际 CSV 解析器(好吧,Semicolon-SV),而不是试图用正则表达式破解某些东西:
#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
use Text::CSV_XS;
my $csv = Text::CSV_XS->new({ binary => 1, sep_char => ";"});
while (my $row = $csv->getline(\*DATA)) {
say $row->[0];
}
__DATA__
"bla ; bla"; bla
"bla "";"" bla"; bla
"bla ";" bla"; bla