正则expression式来分割CSV

我知道这个(或类似的)已被问了很多次,但已经尝试了许多可能性,我一直没能find一个正常工作100%的正则expression式。

我有一个CSV文件,我试图把它分成一个数组,但遇到两个问题:引号和空元素。

CSV看起来像:

123,2.99,AMO024,Title,"Description, more info",,123987564 

我尝试使用的正则expression式是:

 thisLine.split(/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/) 

唯一的问题是,在我的输出数组中第五个元素出来123987564而不是一个空string。

描述

而不是使用拆分,我认为简单地执行匹配并处理所有find的匹配会更容易。

这个expression会:

  • 将您的示例文本划分为逗号分隔符
  • 将处理空值
  • 会忽略双引号,提供双引号不嵌套
  • 修剪返回的值的分隔逗号
  • 从返回的值中修剪引号

正则expression式: (?:^|,)(?=[^"]|(")?)"?((?(1)[^"]*|[^,"]*))"?(?=,|$)

在这里输入图像描述

示例文本

 123,2.99,AMO024,Title,"Description, more info",,123987564 

使用非javaexpression式的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 

使用非javaexpression式匹配

组0获取包含逗号的整个子string
如果使用了第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 

几个月前我创build了这个项目。

  ".+?"|[^"]+?(?=,)|(?<=,)[^"]+ 

正则表达式可视化

它在C#中工作,当selectPython和PCRE时,Debuggex很高兴。 Javascript不能识别这种forms的Proceeded By ?<= …。

对于你的价值观,它会创造匹配

 123 ,2.99 ,AMO024 ,Title "Description, more info" , ,123987564 

请注意,引号中的任何内容都没有前导逗号,但是尝试与前导逗号匹配是空值用例所必需的。 完成后,根据需要修改值。

我使用RegexHero.Net来testing我的正则expression式。

我也需要这个答案,但是我find了答案,而信息丰富,有点难以遵循和复制其他语言。 这是我为CSV列中的一列提出的最简单的expression式。 我不是分裂。 我build立一个正则expression式来匹配一个CSV列,所以我不分裂线:

 ("([^"]*)"|[^,]*)(,|$) 

这与CSV行中的单个列匹配。 expression式的第一部分"([^"]*)"是匹配一个引用的条目,第二部分[^,]*是匹配一个非引用的条目。 。

并附带debuggex来testingexpression式。

https://www.debuggex.com/r/s4z_Qi2gZiyzpAhx

将JScript用于传统的ASP页面的优点是可以使用为JavaScript编写的许多库中的一个。

像这样的: https : //github.com/gkindel/CSV-JS 。 下载它,将其包含在你的ASP页面,parsingCSV。

 <%@ 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> 

我个人尝试了许多RegExexpression式,却没有find与所有情况匹配的完美expression式。

我认为正则expression式很难正确configuration以正确匹配所有情况。 尽pipe很less有人不喜欢这个名字空间(我也是他们的一部分),但是我提出了一些属于.Net框架的东西,并且在所有情况下都给出了适当的结果(主要处理每个双引号的情况):

Microsoft.VisualBasic.FileIO.TextFieldParser

在这里find它: 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) { ... 

希望它可以帮助。

在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," 

缺点:不工作,当列有奇数的报价:(

还有一些额外的function,比如支持包含转义引号和CR / LF字符(单个值跨越多行)的引用值。

注意:尽pipe下面的解决scheme可能适用于其他正则expression式引擎,但是按原样使用它将需要您的正则expression式引擎将多个命名的捕获组与同一个名称作为一个捕获组对待。 (.NET默认是这样做的)


当CSV文件/stream(匹配RFC标准4180 )的多行/logging传递给下面的正则expression式时,它将返回每个非空行/logging的匹配。 每个匹配将包含一个名为Value的捕获组,该捕获组包含该行/logging中的捕获值(如果在行/loggingOpenValue有开放引用,则可能包含OpenValue捕获组)

这是注释模式( 在Regexstorm.net上testing ):

 (?<=\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|$) 

以下是来自Debuggex.com的一个可视化文件 (为了清楚起见而命名的捕获组): Debuggex.com可视化

有关如何使用正则expression式模式的示例可以在我的答案中find类似的问题,也可以在这里或在这里的 C#平台上 find 。

我迟到了,但以下是我使用的正则expression式:

 (?:,"|^")(""|[\w\W]*?)(?=",|"$)|(?:,(?!")|^(?!"))([^,]*?)(?=$|,)|(\r\n|\n) 

这种模式有三个捕获组:

  1. 引用的单元格的内容
  2. 没有引号的单元格的内容
  3. 一条新的线

该模式处理以下所有内容:

  • 正常的单元格内容没有任何特殊的function: 一,二,三
  • 包含双引号的单元格(“转义为”): 不引用,“a”,“引用”,“结束”
  • 单元格包含一个换行符: 一个,两个\ nthree,四个
  • 正常的单元格内容有一个内部引用: 一个,两个“三个,四个
  • 单元格包含引号,后跟逗号: 1,“2”,“3”,“4”,5

看到这个模式在使用。

如果你正在使用正则expression式更有效的风格与命名组和lookbehinds,我更喜欢以下内容:

 (?<quoted>(?<=,"|^")(?:""|[\w\W]*?)*(?=",|"$))|(?<normal>(?<=,(?!")|^(?!"))[^,]*?(?=(?<!")$|(?<!"),))|(?<eol>\r\n|\n) 

看到这个模式在使用。

我正在使用这个,它与昏迷分离器和双引号转义。 通常这应该解决你的问题:

 /(?<=^|,)(\"(?:[^"]+|"")*\"|[^,]*)(?:$|,)/g 

我有类似的需要从SQL插入语句拆分CSV值。

在我的情况下,我可以假定string被包裹在单引号中,而数字不是。

 csv.split(/,((?=')|(?=\d))/g).filter(function(x) { return x !== '';}); 

一些可能是显而易见的原因,这个正则expression式产生一些空白的结果。 我可以忽略这些,因为我的数据中的任何空值都表示为...,'',...而不是...,,...

如果我使用'g'标志尝试@chubbsondubs在http://regex101.com上发布的正则expression式,那么匹配项只包含','或一个空string&#x3002; 有了这个正则expression式:
(?:"([^"]*)"|([^,]*))(?:[,])
我可以匹配CSV的部分(包括引用的部分)。 (该行必须以','结尾,否则最后一部分不被识别。)
https://regex101.com/r/dF9kQ8/4
如果CSV看起来像:
"",huhu,"hel lo",world,
有4场比赛:
“”
“忽忽”
'你好'
'世界'

如果你知道你不会有一个空的字段(,,),那么这个expression效果很好:

 ("[^"]*"|[^,]+) 

如下例所示…

 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 

但是,如果预计空字段和文本相对较小,则可能需要考虑在parsing之前先用空格replace空字段,以确保它们被捕获。 例如…

 ... Set col = rx.Execute(Replace(sText, ",,", ", ,")) ... 

如果您需要保持字段的完整性,则可以恢复逗号并testing循环中的空白空间。 这可能不是最有效的方法,但它完成了工作。

 ,?\s*'.+?'|,?\s*".+?"|[^"']+?(?=,)|[^"']+ 

这个正则expression式适用于单引号和双引号,也可以在另一个引号内引用。

这一个匹配所有我需要在C#中:

 (?<=(^|,)(?<quote>"?))([^"]|(""))*?(?=\<quote>(?=,|$)) 
  • 去掉报价
  • 让新的线
  • 让引号内的string加双引号
  • 让引号中的逗号string

使用正确的正则expression式将单引号值与单引号中的转义[doubled]单引号匹配:

 '([^n']|(''))+'