56

これ(または同様のもの)が何度も尋ねられたことは知っていますが、多くの可能性を試してみましたが、100%機能する正規表現を見つけることができませんでした。

CSV ファイルがあり、それを配列に分割しようとしていますが、引用符で囲まれたコンマと空の要素という 2 つの問題が発生しています。

CSV は次のようになります。

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

私が使用しようとした正規表現は次のとおりです。

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

唯一の問題は、出力配列で 5 番目の要素が空の文字列ではなく 123987564 として出力されることです。

4

18 に答える 18

64

説明

分割を使用する代わりに、単純に一致を実行して、見つかったすべての一致を処理する方が簡単だと思います。

この式は次のようになります。

  • サンプル テキストをカンマ区切りで分割します
  • 空の値を処理します
  • 二重引用符がネストされていない場合、二重引用符で囲まれたコンマは無視されます
  • 戻り値から区切りコンマを削除します
  • 戻り値から周囲の引用符を削除します

正規表現: (?:^|,)(?=[^"]|(")?)"?((?(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
于 2013-08-09T12:51:14.883 に答える
13

プロジェクトのために数か月前にこれを作成しました。

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

正規表現の視覚化

C# で動作し、Python と PCRE を選択したときの Debuggex は満足のいくものでした。Javascript は、この形式の Proceeded By ?<=...を認識しません。

あなたの価値のために、それはで一致を作成します

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

引用符で囲まれたものには先頭のコンマがありませんが、空の値の使用例では先頭のコンマとの一致を試みる必要があることに注意してください。完了したら、必要に応じて値をトリムします。

RegexHero.Netを使用して正規表現をテストします。

于 2015-08-26T16:29:15.573 に答える
9

私もこの回答が必要でしたが、回答は参考になりましたが、他の言語でフォローして複製するのは少し難しいことがわかりました。これは、CSV 行の 1 つの列に対して思いついた最も単純な式です。私は分割していません。CSV の列に一致する正規表現を作成しているので、行を分割していません。

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

これは、CSV 行の 1 つの列と一致します。式の最初の部分"([^"]*)"は引用されたエントリに一致し、2 番目の部分[^,]*は引用されていないエントリに一致します。その後に a,または end of lineが続き$ます。

そして、式をテストするための付属の debuggex。

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

于 2014-10-27T17:01:15.583 に答える
4

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

短所:列に奇数の引用符がある場合、機能しません:(

于 2015-02-06T19:41:28.027 に答える
3

従来の ASP ページに JScript を使用する利点は、JavaScript 用に作成された非常に多くのライブラリの 1 つを使用できることです。

このように: 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>
于 2013-08-09T10:56:47.210 に答える
2

エスケープされた引用符と CR/LF 文字 (複数行にまたがる単一の値) を含む引用符付きの値のサポートなど、いくつかの追加機能を備えたさらに別の回答。

注: 以下のソリューションは他の正規表現エンジンに適用できる可能性がありますが、そのまま使用するには、正規表現エンジンが同じ名前を使用する複数の名前付きキャプチャ グループを1 つのキャプチャ グループとして扱う必要があります。(.NET は既定でこれを行います)


CSV ファイル/ストリーム ( RFC 標準 4180に一致) の複数の行/レコードが以下の正規表現に渡されると、空でない各行/レコードに対して一致が返されます。各一致にはValue、その行/レコードでキャプチャされた値を含むという名前のキャプチャ グループが含まれます (行/レコードの末尾に開いた引用符があった場合は、キャプチャ グループも含まれる可能性OpenValueがあります) 。

コメント付きのパターンは次のとおりです ( 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|$)

[これは Debuggex.com からの視覚化です][3] (わかりやすくするために名前を付けたキャプチャ グループ): ![Debuggex.com の視覚化][4]

正規表現パターンの使用方法の例は、同様の質問に対する私の回答(こちら)、またはC# パッド (こちら)、または (こちら) にあります。

于 2016-10-01T17:42:42.513 に答える
1

空のフィールド (,,) がないことがわかっている場合は、次の式がうまく機能します。

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

次の例のように...

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

ただし、空のフィールドが予想され、テキストが比較的小さい場合は、解析する前に空のフィールドをスペースに置き換えて、それらが確実にキャプチャされるようにすることを検討してください。例えば...

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

また、フィールドの整合性を維持する必要がある場合は、カンマを元に戻し、ループ内の空白をテストできます。これは最も効率的な方法ではないかもしれませんが、仕事は完了します。

于 2016-08-11T19:42:53.600 に答える
0
,?\s*'.+?'|,?\s*".+?"|[^"']+?(?=,)|[^"']+  

この正規表現は、一重引用符と二重引用符、および別の引用符内の 1 つの引用符でも機能します!

于 2016-10-14T21:05:28.583 に答える
0

同様に、SQL 挿入ステートメントから CSV 値を分割する必要がありました。

私の場合、文字列は一重引用符で囲まれ、数字はそうではないと想定できました。

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

おそらく明白な理由で、この正規表現はいくつかの空白の結果を生成します。データ内の空の値は として表され...,'',...、 ではなかったので、これらは無視できまし...,,...た。

于 2014-03-14T16:25:02.063 に答える