私はこれ(または同様の)が何度も尋ねられたことを知っていますが、多くの可能性を試しましたが、100%動作する正規表現を見つけることができませんでした。
CSVファイルを取得し、それを配列に分割しようとしていますが、引用符付きのコンマと空の要素という2つの問題が発生しています。
CSVは次のようになります。
123,2.99,AMO024,Title,"Description, more info",,123987564
私が使用しようとした正規表現は次のとおりです。
thisLine.split(/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/)
唯一の問題は、出力配列で、5番目の要素が123987564として出力され、空の文字列ではないことです。
分割を使用する代わりに、単に一致を実行し、見つかった一致をすべて処理する方が簡単だと思います。
この式は:
正規表現:(?:^|,)(?=[^"]|(")?)"?((?(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
これに少し取り組んで、このソリューションを思い付きました:
(?:,|\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'"""
仕組みの説明 を次に示します。
(?:,|\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
)
数か月前にプロジェクト用に作成しました。
".+?"|[^"]+?(?=,)|(?<=,)[^"]+
C#で動作し、DebuggexはPythonおよびPCREを選択したときに満足しました。Javascriptはこの形式のProceeded By?<= ...を認識しません... 。
あなたの値については、上のマッチを作成します
123
,2.99
,AMO024
,Title
"Description, more info"
,
,123987564
引用符で囲まれたものには先頭にコンマがないことに注意してください。ただし、空の値のユースケースでは、先頭のコンマと一致させる必要があります。完了したら、必要に応じて値をトリミングします。
RegexHero.Net を使用して、正規表現をテストします。
私もこの答えが必要でしたが、答えは有益でありながら、他の言語に合わせて再現するのが少し難しいと思いました。以下は、CSV行の1つの列について考えた最も単純な式です。私は分裂していません。 CSVの列に一致する正規表現を作成しているので、行を分割しません。
_("([^"]*)"|[^,]*)(,|$)
_
これは、CSV行の単一の列と一致します。式の最初の"([^"]*)"
部分は引用符で囲まれたエントリと一致し、2番目の部分_[^,]*
_は引用符で囲まれていないエントリと一致します。次に、_,
_または行の終わり_$
_が続きます。
そして、式をテストするための付随するdebuggex。
私はパーティーに遅れていますが、私が使用している正規表現は次のとおりです。
(?:,"|^")(""|[\w\W]*?)(?=",|"$)|(?:,(?!")|^(?!"))([^,]*?)(?=$|,)|(\r\n|\n)
このパターンには3つのキャプチャグループがあります。
このパターンは、次のすべてを処理します。
名前付きグループとルックビハインドを備えた、より有能な正規表現を使用している場合、私は次のことを好みます:
(?<quoted>(?<=,"|^")(?:""|[\w\W]*?)*(?=",|"$))|(?<normal>(?<=,(?!")|^(?!"))[^,]*?(?=(?<!")$|(?<!"),))|(?<eol>\r\n|\n)
編集
(?:^"|,")(""|[\w\W]*?)(?=",|"$)|(?:^(?!")|,(?!"))([^,]*?)(?=$|,)|(\r\n|\n)
このわずかに変更されたパターンは、Javascriptを使用していない限り、最初の列が空の行を処理します。何らかの理由で、Javascriptはこのパターンの2番目の列を省略します。このエッジケースを正しく処理できませんでした。
個人的には、すべてのケースに一致する完璧な表現を見つけることなく、多くの正規表現を試しました。
すべてのケースに適切に一致するように正規表現を適切に構成するのは難しいと思います。名前空間を気に入らない人はほとんどいません(私もその一部でした)。
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)
{
...
それが役立つことを願っています。
従来のASPページにJScriptを使用する利点は、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>
In Java this pattern ",(?=([^\"]*\"[^\"]*\")*(?![^\"]*\"))"
almost work for me:
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,"
欠点:列の引用符の数が奇数の場合、機能しません:(
Aaaと別の答えはこちら。 :)他のquiteを動作させることができなかったので。
私の解決策は両方ともエスケープされた引用符(二重発生)を処理し、マッチに区切り文字を含めません。
注意してください'
の代わりに "
それは私のシナリオでしたが、同じ効果を得るためにパターンで単純に置き換えてください。
ここに行きます(「ホワイトスペースを無視」フラグを使用することを忘れないでください/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}|[^']+)+')(?=,|$)
私はこれを使用しています。これは、コマ区切りと二重引用符エスケープで動作します。通常、それはあなたの問題を解決するはずです:
/(?<=^|,)(\"(?:[^"]+|"")*\"|[^,]*)(?:$|,)/g
エスケープされた引用符とCR/LF文字(複数行にわたる単一の値)を含む引用符で囲まれた値のサポートなど、いくつかの追加機能を備えたさらに別の回答。
注:以下のソリューションは他の正規表現エンジンに適応する可能性がありますが、それを使用してas-is正規表現エンジンが 同じ名前を使用する複数の名前付きキャプチャグループ を1つの単一キャプチャグループとして扱う必要があります。 (.NETはデフォルトでこれを行います)
CSVファイル/ストリームの複数の行/レコード(一致する RFC標準418 )が下の正規表現に渡されると、空でない各行/レコードの一致が返されます。各一致には、その行/レコードにキャプチャされた値を含む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からの視覚化です (わかりやすくするために名前を付けたキャプチャグループ):
正規表現パターンの使用方法の例は、同様の質問への回答 here 、または C#pad here 、または here にあります。
,?\s*'.+?'|,?\s*".+?"|[^"']+?(?=,)|[^"']+
この正規表現は、一重引用符と二重引用符、および別の引用符の内側で使用できます!
空のフィールド(,)がないことがわかっている場合、この式はうまく機能します。
("[^"]*"|[^,]+)
次の例のように...
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, ",,", ", ,"))
...
また、フィールドの整合性を維持する必要がある場合は、カンマを復元して、ループ内の空のスペースをテストできます。これは最も効率的な方法ではないかもしれませんが、仕事は完了します。
@ -chubbsondubsが http://regex101.com で 'g'フラグを使用して投稿した正規表現を試してみると、 '、'または空の文字列のみを含む一致があります。この正規表現では:(?:"([^"]*)"|([^,]*))(?:[,])
iはCSVの部分と一致できます(引用部分を含む)。 (行は「、」で終了する必要があります。そうでない場合、最後の部分は認識されません。)
https://regex101.com/r/dF9kQ8/4
CSVが次のような場合:"",huhu,"hel lo",world,
4つの一致があります。
」
'huhu'
'こんにちは'
'世界'
これは私がC#で必要とするすべてに一致します:
(?<=(^|,)(?<quote>"?))([^"]|(""))*?(?=\<quote>(?=,|$))
同様に、SQL挿入ステートメントからCSV値を分割する必要がありました。
私の場合、文字列は単一引用符で囲まれ、数値は囲まれていないと想定できます。
csv.split(/,((?=')|(?=\d))/g).filter(function(x) { return x !== '';});
おそらく明白な理由のために、この正規表現は空白の結果を生成します。データ内の空の値は...,'',...
ではなく...,,...
として表されていたため、それらを無視できました。