我知道这个(或类似的)已被多次询问,但尝试了很多可能性,但我找不到100%正常工作的正则表达式。
我有一个CSV文件,我正在尝试将其拆分为数组,但遇到两个问题:引用逗号和空元素。
CSV看起来像:
123,2.99,AMO024,Title,"Description, more info",,123987564
我试图使用的正则表达式是:
thisLine.split(/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/)
唯一的问题是在我的输出数组中,第5个元素是123987564而不是空字符串。
答案 0 :(得分:44)
除了使用拆分之外,我认为简单地执行匹配并处理所有找到的匹配会更容易。
此表达式将:
正则表达式:(?:^|,)(?=[^"]|(")?)"?((?(1)[^"]*|[^,"]*))"?(?=,|$)
示例文字
123,2.99,AMO024,Title,"Description, more info",,123987564
使用非java表达式的ASP示例
Set regEx = New RegExp
regEx.Global = True
regEx.IgnoreCase = True
regEx.MultiLine = True
sourcestring = "your source string"
regEx.Pattern = "(?:^|,)(?=[^""]|("")?)""?((?(1)[^""]*|[^,""]*))""?(?=,|$)"
Set Matches = regEx.Execute(sourcestring)
For z = 0 to Matches.Count-1
results = results & "Matches(" & z & ") = " & chr(34) & Server.HTMLEncode(Matches(z)) & chr(34) & chr(13)
For zz = 0 to Matches(z).SubMatches.Count-1
results = results & "Matches(" & z & ").SubMatches(" & zz & ") = " & chr(34) & Server.HTMLEncode(Matches(z).SubMatches(zz)) & chr(34) & chr(13)
next
results=Left(results,Len(results)-1) & chr(13)
next
Response.Write "<pre>" & results
使用非java表达式匹配
组0获取包含逗号
的整个子字符串
如果使用了第1组,则获得报价
第2组获得的值不包括逗号
[0][0] = 123
[0][1] =
[0][2] = 123
[1][0] = ,2.99
[1][1] =
[1][2] = 2.99
[2][0] = ,AMO024
[2][1] =
[2][2] = AMO024
[3][0] = ,Title
[3][1] =
[3][2] = Title
[4][0] = ,"Description, more info"
[4][1] = "
[4][2] = Description, more info
[5][0] = ,
[5][1] =
[5][2] =
[6][0] = ,123987564
[6][1] =
[6][2] = 123987564
答案 1 :(得分:8)
稍微研究了一下这个解决方案:
(?:,|\n|^)("(?:(?:"")*[^"]*)*"|[^",\n]*|(?:\n|$))
此解决方案处理“漂亮”的CSV数据,如
"a","b",c,"d",e,f,,"g"
0: "a"
1: "b"
2: c
3: "d"
4: e
5: f
6:
7: "g"
和更加丑陋的事情如
"""test"" one",test' two,"""test"" 'three'","""test 'four'"""
0: """test"" one"
1: test' two
2: """test"" 'three'"
3: """test 'four'"""
这是explanation of how it works:
(?:,|\n|^) # all values must start at the beginning of the file,
# the end of the previous line, or at a comma
( # single capture group for ease of use; CSV can be either...
" # ...(A) a double quoted string, beginning with a double quote (")
(?: # character, containing any number (0+) of
(?:"")* # escaped double quotes (""), or
[^"]* # non-double quote characters
)* # in any order and any number of times
" # and ending with a double quote character
| # ...or (B) a non-quoted value
[^",\n]* # containing any number of characters which are not
# double quotes ("), commas (,), or newlines (\n)
| # ...or (C) a single newline or end-of-file character,
# used to capture empty values at the end of
(?:\n|$) # the file or at the ends of lines
)
答案 2 :(得分:7)
我也需要这个答案,但我找到了答案,虽然提供了信息,但有点难以理解和复制其他语言。这是我为CSV行中的单个列提出的最简单的表达式。我没有分裂。我正在构建一个正则表达式以匹配CSV中的列,所以我不会拆分该行:
("([^"]*)"|[^,]*)(,|$)
这匹配CSV行中的单个列。表达式的第一部分"([^"]*)"
用于匹配带引号的条目,第二部分[^,]*
用于匹配未引用的条目。然后是,
或行尾$
。
随附的debuggex来测试表达式。
答案 3 :(得分:6)
我迟到了,但以下是我使用的正则表达式:
(?:,"|^")(""|[\w\W]*?)(?=",|"$)|(?:,(?!")|^(?!"))([^,]*?)(?=$|,)|(\r\n|\n)
此模式有三个捕获组:
此模式处理以下所有内容:
如果您正在使用具有命名组和外观的更强大的正则表达式,我更喜欢以下内容:
(?<quoted>(?<=,"|^")(?:""|[\w\W]*?)*(?=",|"$))|(?<normal>(?<=,(?!")|^(?!"))[^,]*?(?=(?<!")$|(?<!"),))|(?<eol>\r\n|\n)
修改强>
(?:^"|,")(""|[\w\W]*?)(?=",|"$)|(?:^(?!")|,(?!"))([^,]*?)(?=$|,)|(\r\n|\n)
这个略微修改的模式处理第一列为空的行,只要您不使用Javascript即可。出于某种原因,Javascript将省略具有此模式的第二列。我无法正确处理这种边缘情况。
答案 4 :(得分:3)
将JScript用于经典ASP页面的优点是,您可以使用为JavaScript编写的众多库中的一个。
像这样:https://github.com/gkindel/CSV-JS。下载它,将其包含在您的ASP页面中,用它解析CSV。
<%@ language="javascript" %>
<script language="javascript" runat="server" src="scripts/csv.js"></script>
<script language="javascript" runat="server">
var text = '123,2.99,AMO024,Title,"Description, more info",,123987564',
rows = CSV.parse(line);
Response.Write(rows[0][4]);
</script>
答案 5 :(得分:3)
我亲自尝试了很多RegEx表达式而没有找到适合所有情况的完美表达。
我认为正则表达式很难正确配置以正确匹配所有情况。 虽然很少有人不喜欢命名空间(我也是其中的一部分),但我提出的内容是.Net框架的一部分,并且在所有情况下始终给我正确的结果(主要是很好地管理每个双引号的情况):
Microsoft.VisualBasic.FileIO.TextFieldParser
在此处找到:StackOverflow
使用示例:
TextReader textReader = new StringReader(simBaseCaseScenario.GetSimStudy().Study.FilesToDeleteWhenComplete);
Microsoft.VisualBasic.FileIO.TextFieldParser textFieldParser = new TextFieldParser(textReader);
textFieldParser.SetDelimiters(new string[] { ";" });
string[] fields = textFieldParser.ReadFields();
foreach (string path in fields)
{
...
希望它可以提供帮助。
答案 6 :(得分:3)
在Java中,这种模式",(?=([^\"]*\"[^\"]*\")*(?![^\"]*\"))"
几乎对我有用:
String text = "\",\",\",,\",,\",asdasd a,sd s,ds ds,dasda,sds,ds,\"";
String regex = ",(?=([^\"]*\"[^\"]*\")*(?![^\"]*\"))";
Pattern p = Pattern.compile(regex);
String[] split = p.split(text);
for(String s:split) {
System.out.println(s);
}
输出:
","
",a,,"
",asdasd a,sd s,ds ds,dasda,sds,ds,"
缺点:当列具有奇数引号时不起作用:(
答案 7 :(得分:2)
Aaaand这里的另一个答案。 :)因为我无法使其他人完全工作。
我的解决方案都处理转义引号(双重引号),并且匹配中不包含分隔符。
请注意,我一直在与'
而不是"
进行匹配,因为这是我的方案,但只是在模式中替换它们以获得相同的效果。
此处(如果您使用下面的注释版本,请记得使用“忽略空白”标记/x
):
# Only include if previous char was start of string or delimiter
(?<=^|,)
(?:
# 1st option: empty quoted string (,'',)
'{2}
|
# 2nd option: nothing (,,)
(?:)
|
# 3rd option: all but quoted strings (,123,)
# (included linebreaks to allow multiline matching)
[^,'\r\n]+
|
# 4th option: quoted strings (,'123''321',)
# start pling
'
(?:
# double quote
'{2}
|
# or anything but quotes
[^']+
# at least one occurance - greedy
)+
# end pling
'
)
# Only include if next char is delimiter or end of string
(?=,|$)
单行版本:
(?<=^|,)(?:'{2}|(?:)|[^,'\r\n]+|'(?:'{2}|[^']+)+')(?=,|$)
答案 8 :(得分:1)
我正在使用这个,它适用于昏迷分隔符和双引号转义。 通常这应该解决你的问题:
/(?<=^|,)(\"(?:[^"]+|"")*\"|[^,]*)(?:$|,)/g
答案 9 :(得分:1)
另一个答案还有一些额外的功能,例如支持包含转义引号和CR / LF字符的引用值(单个值跨越多行)。
注意:虽然以下解决方案可能适用于其他正则表达式引擎,但使用 as-is 将要求您的正则表达式引擎将multiple named capture groups using the same name视为一个单一的捕获组。 (.NET默认执行此操作)
当CSV文件/流的多行/记录(匹配RFC standard 4180)传递给下面的正则表达式时,它将返回每个非空行/记录的匹配项。每个匹配项都将包含一个名为Value
的捕获组,其中包含该行/记录中捕获的值(如果在行尾有一个打开的引号,则可能包含OpenValue
捕获组记录)
这是注释模式(测试它on Regexstorm.net):
(?<=\r|\n|^)(?!\r|\n|$) // Records start at the beginning of line (line must not be empty)
(?: // Group for each value and a following comma or end of line (EOL) - required for quantifier (+?)
(?: // Group for matching one of the value formats before a comma or EOL
"(?<Value>(?:[^"]|"")*)"| // Quoted value -or-
(?<Value>(?!")[^,\r\n]+)| // Unquoted value -or-
"(?<OpenValue>(?:[^"]|"")*)(?=\r|\n|$)| // Open ended quoted value -or-
(?<Value>) // Empty value before comma (before EOL is excluded by "+?" quantifier later)
)
(?:,|(?=\r|\n|$)) // The value format matched must be followed by a comma or EOL
)+? // Quantifier to match one or more values (non-greedy/as few as possible to prevent infinite empty values)
(?:(?<=,)(?<Value>))? // If the group of values above ended in a comma then add an empty value to the group of matched values
(?:\r\n|\r|\n|$) // Records end at EOL
这是没有所有注释或空格的原始模式。
(?<=\r|\n|^)(?!\r|\n|$)(?:(?:"(?<Value>(?:[^"]|"")*)"|(?<Value>(?!")[^,\r\n]+)|"(?<OpenValue>(?:[^"]|"")*)(?=\r|\n|$)|(?<Value>))(?:,|(?=\r|\n|$)))+?(?:(?<=,)(?<Value>))?(?:\r\n|\r|\n|$)
Here is a visualization from Debuggex.com(为清晰起见而命名的捕获组):
有关如何使用正则表达式模式的示例,请参阅我对类似问题here或C# pad here或here的回答。
答案 10 :(得分:0)
我使用这个表达。它考虑了我遇到的逗号后的空格。
(?:,"|^"|, ")(""|[\w\W]*?)(?=",|"$)|(?:,(?!")|^(?!"))([^,]*?)(?=$|,)|(\r\n|\n)
答案 11 :(得分:0)
这个匹配c#所需的全部内容:
(?<=(^|,)(?<quote>"?))([^"]|(""))*?(?=\<quote>(?=,|$))
答案 12 :(得分:0)
,?\s*'.+?'|,?\s*".+?"|[^"']+?(?=,)|[^"']+
这个正则表达式适用于单引号和双引号,也适用于另一个引用!
答案 13 :(得分:0)
如果你知道你没有空字段(,,)那么这个表达式效果很好:
Route::delete('/project/{project}', function (Project $project) {
DB::table('pics')->where('projectId', '=', $project->id)->delete();
$project -> delete();
return redirect('/');
});
如下例所示......
("[^"]*"|[^,]+)
但是,如果您预计空字段并且文本相对较小,则可能会考虑在解析之前用空格替换空字段以确保捕获它们。例如......
Set rx = new RegExp
rx.Pattern = "(""[^""]*""|[^,]+)"
rx.Global = True
Set col = rx.Execute(sText)
For n = 0 to col.Count - 1
if n > 0 Then s = s & vbCrLf
s = s & col(n)
Next
如果您需要维护字段的完整性,可以恢复逗号并测试循环内的空白区域。这可能不是最有效的方法,但它可以完成工作。
答案 14 :(得分:0)
如果我在http://regex101.com上使用&#39; g&#39;尝试@chubbsondubs发布的正则表达式flag,有匹配,只包含&#39;,&#39;或一个空字符串。
使用此正则表达式:
(?:"([^"]*)"|([^,]*))(?:[,])
我可以匹配CSV的各个部分(包含引用的部分)。 (该行必须以&#39;终止,否则最后一部分不会被识别。)
https://regex101.com/r/dF9kQ8/4
如果CSV看起来像:
"",huhu,"hel lo",world,
有4场比赛:
&#39;&#39;
&#39;乎乎&#39;
&#39; hel lo&#39;
&#39;世界&#39;
答案 15 :(得分:0)
我有类似的需要从SQL插入语句中拆分CSV值。
在我的情况下,我可以假设字符串用单引号括起来而且数字不是。
csv.split(/,((?=')|(?=\d))/g).filter(function(x) { return x !== '';});
由于一些可能明显的原因,这个正则表达式会产生一些空白结果。我可以忽略这些,因为我的数据中的任何空值都表示为...,'',...
而不是...,,...
。
答案 16 :(得分:-11)
正确的正则表达式匹配单个带引号的值与其中的转义[doubled]单引号:
'([^n']|(''))+'