Ich weiß, dass (oder ähnlich) oft gefragt wurde, aber nachdem ich zahlreiche Möglichkeiten ausprobiert hatte, konnte ich keinen Regex finden, der zu 100% funktioniert.
Ich habe eine CSV-Datei und versuche, sie in ein Array aufzuteilen, dabei treten jedoch zwei Probleme auf: Anführungszeichen und leere Elemente.
Der CSV sieht so aus:
123,2.99,AMO024,Title,"Description, more info",,123987564
Die Regex, die ich versucht habe, ist:
thisLine.split(/,(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))/)
Das einzige Problem ist, dass das 5. Element in meinem Ausgabearray als 123987564 und nicht als leerer String ausgegeben wird.
Anstatt einen Split zu verwenden, denke ich, wäre es einfacher, einfach ein Match auszuführen und alle gefundenen Matches zu verarbeiten.
Dieser Ausdruck wird:
Regex: (?:^|,)(?=[^"]|(")?)"?((?(1)[^"]*|[^,"]*))"?(?=,|$)
Beispieltext
123,2.99,AMO024,Title,"Description, more info",,123987564
ASP Beispiel mit dem Nicht-Java-Ausdruck
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
Übereinstimmungen mit dem Nicht-Java-Ausdruck
Gruppe 0 erhält den gesamten Teilstring, der das Komma enthält
Gruppe 1 erhält das Zitat, wenn es verwendet wird
Gruppe 2 erhält den Wert ohne Komma
[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
Ich habe dies vor einigen Monaten für ein Projekt erstellt.
".+?"|[^"]+?(?=,)|(?<=,)[^"]+
Es funktioniert in C # und das Debuggex war glücklich, als ich Python und PCRE auswählte. Javascript erkennt diese Form von Proceeded By ? <= ... nicht.
Für Ihre Werte werden Übereinstimmungen erstellt
123
,2.99
,AMO024
,Title
"Description, more info"
,
,123987564
Beachten Sie, dass alles in Anführungszeichen kein führendes Komma enthält, aber der Versuch, ein führendes Komma zu finden, war für den Anwendungsfall für leere Werte erforderlich. Trimmen Sie anschließend die Werte nach Bedarf.
Ich benutze RegexHero.Net , um mein Regex zu testen.
Ich brauchte diese Antwort auch, aber ich fand die Antworten, obwohl sie informativ waren, etwas schwer zu folgen und für andere Sprachen zu replizieren. Hier ist der einfachste Ausdruck, den ich für eine einzelne Spalte der CSV-Zeile gefunden habe. Ich spalte nicht Ich baue einen Regex, der mit einer Spalte aus dem CSV übereinstimmt, so dass ich die Linie nicht spalte:
("([^"]*)"|[^,]*)(,|$)
Dies entspricht einer einzelnen Spalte aus der CSV-Zeile. Der erste Teil "([^"]*)"
des Ausdrucks soll mit einem Eintrag in Anführungszeichen übereinstimmen, der zweite Teil [^,]*
soll mit einem nicht in Anführungszeichen enthaltenen Eintrag übereinstimmen. Dann entweder gefolgt von einem ,
oder dem Zeilenende $
.
Und das begleitende Debuggex, um den Ausdruck zu testen.
Ich habe ein bisschen daran gearbeitet und kam zu dieser Lösung:
(?:,|\n|^)("(?:(?:"")*[^"]*)*"|[^",\n]*|(?:\n|$))
Diese Lösung verarbeitet "nette" CSV-Daten wie
"a","b",c,"d",e,f,,"g"
0: "a"
1: "b"
2: c
3: "d"
4: e
5: f
6:
7: "g"
und hässlichere Dinge mögen
"""test"" one",test' two,"""test"" 'three'","""test 'four'"""
0: """test"" one"
1: test' two
2: """test"" 'three'"
3: """test 'four'"""
Hier ist eine Erklärung, wie es funktioniert :
(?:,|\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
)
Ich bin spät dran, aber Folgendes ist der reguläre Ausdruck, den ich verwende:
(?:,"|^")(""|[\w\W]*?)(?=",|"$)|(?:,(?!")|^(?!"))([^,]*?)(?=$|,)|(\r\n|\n)
Dieses Muster hat drei Erfassungsgruppen:
Dieses Muster behandelt Folgendes:
Sehen Sie dieses Muster in Verwendung.
Wenn Sie mit benannten Gruppen und Lookbehinds eine leistungsfähigere Variante von Regex verwenden, bevorzuge ich Folgendes:
(?<quoted>(?<=,"|^")(?:""|[\w\W]*?)*(?=",|"$))|(?<normal>(?<=,(?!")|^(?!"))[^,]*?(?=(?<!")$|(?<!"),))|(?<eol>\r\n|\n)
Sehen Sie dieses Muster in Verwendung.
Bearbeiten
(?:^"|,")(""|[\w\W]*?)(?=",|"$)|(?:^(?!")|,(?!"))([^,]*?)(?=$|,)|(\r\n|\n)
Dieses leicht modifizierte Muster behandelt Zeilen, in denen die erste Spalte leer ist, solange Sie kein Javascript verwenden. Aus irgendeinem Grund lässt Javascript die zweite Spalte dieses Musters weg. Ich konnte diesen Edge-Fall nicht richtig bearbeiten.
Ich persönlich habe viele RegEx-Ausdrücke ausprobiert, ohne für jeden Fall den passenden Ausdruck gefunden zu haben.
Ich denke, dass reguläre Ausdrücke schwer zu konfigurieren sind, um alle Fälle richtig abzugleichen. Obwohl der Namespace nur wenigen Personen gefällt (und ich war ein Teil davon), schlage ich etwas vor, das Teil des .NET-Frameworks ist, und gebe mir in allen Fällen zu allen Zeiten richtige Ergebnisse (meistens werden alle Anführungszeichen sehr gut verarbeitet):
Microsoft.VisualBasic.FileIO.TextFieldParser
Fand es hier: StackOverflow
Verwendungsbeispiel:
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)
{
...
Ich hoffe es könnte helfen.
Die Verwendung von JScript für klassische ASP - Seiten hat den Vorteil, dass Sie eine der vielen Bibliotheken verwenden können, die für JavaScript geschrieben wurden.
Wie dieser hier: https://github.com/gkindel/CSV-JS . Laden Sie es herunter, fügen Sie es in Ihre ASP -Seite ein, analysieren Sie CSV damit.
<%@ 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 arbeitet dieses Muster ",(?=([^\"]*\"[^\"]*\")*(?![^\"]*\"))"
fast für mich:
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);
}
ausgabe:
","
",a,,"
",asdasd a,sd s,ds ds,dasda,sds,ds,"
Nachteil: funktioniert nicht, wenn die Spalte eine ungerade Anzahl von Anführungszeichen hat :(
Aaaund noch eine Antwort hier. :) Da ich die anderen nicht ziemlich zum Laufen bringen konnte.
Meine Lösung behandelt sowohl mit Escapezeichen versehene Anführungszeichen (doppelte Vorkommen) als auch Trennzeichen in der Übereinstimmung.
Beachten Sie, dass ich mit '
statt "
verglichen habe, da dies mein Szenario war, aber ersetzen Sie sie einfach im Muster, um denselben Effekt zu erzielen.
Hier geht es (denken Sie daran, das Kennzeichen "Whorepace ignorieren" /x
zu verwenden, wenn Sie die kommentierte Version verwenden):
# 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
(?=,|$)
Einzeilige Version:
(?<=^|,)(?:'{2}|(?:)|[^,'\r\n]+|'(?:'{2}|[^']+)+')(?=,|$)
Ich verwende dieses, es funktioniert mit einem Koma-Trennzeichen und einem doppelten Anführungszeichen.
/(?<=^|,)(\"(?:[^"]+|"")*\"|[^,]*)(?:$|,)/g
Eine weitere Antwort mit einigen zusätzlichen Funktionen wie der Unterstützung von Werten in Anführungszeichen, die Anführungszeichen und CR/LF-Zeichen enthalten (einzelne Werte, die mehrere Zeilen umfassen).
ANMERKUNG: Obwohl die unten stehende Lösung wahrscheinlich für andere Regex-Engines angepasst werden kann, erfordert dies die Verwendung von as-is Ihre Regex-Engine behandelt mehrere benannte Erfassungsgruppen mit demselben Namen als eine einzelne Erfassungsgruppe. (.NET macht dies standardmäßig)
Wenn mehrere Zeilen/Datensätze einer CSV-Datei/eines CSV-Streams (Matching RFC-Standard 418 ) an den regulären Ausdruck darunter übergeben werden, wird für jede nicht leere Zeile/jeden Datensatz eine Übereinstimmung zurückgegeben. Jede Übereinstimmung enthält eine Erfassungsgruppe mit dem Namen Value
, die die erfassten Werte in dieser Zeile/Datensatz enthält (und möglicherweise eine Erfassungsgruppe OpenValue
, wenn am Ende von ein offenes Zitat vorhanden war die Zeile/Aufzeichnung).
Hier ist das kommentierte Muster (teste es auf 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
Hier ist das Rohmuster ohne alle Kommentare oder Leerzeichen.
(?<=\r|\n|^)(?!\r|\n|$)(?:(?:"(?<Value>(?:[^"]|"")*)"|(?<Value>(?!")[^,\r\n]+)|"(?<OpenValue>(?:[^"]|"")*)(?=\r|\n|$)|(?<Value>))(?:,|(?=\r|\n|$)))+?(?:(?<=,)(?<Value>))?(?:\r\n|\r|\n|$)
Hier ist eine Visualisierung von Debuggex.com (Capture-Gruppen, die der Klarheit halber benannt wurden):
Beispiele zur Verwendung des Regex-Musters finden Sie in meiner Antwort auf eine ähnliche Frage hier oder auf C # -Pad hier oder hier .
,?\s*'.+?'|,?\s*".+?"|[^"']+?(?=,)|[^"']+
Diese Regex funktioniert mit einfachen und doppelten Anführungszeichen und auch für ein Zitat innerhalb eines anderen!
Wenn Sie wissen, dass Sie kein leeres Feld (,) haben, funktioniert dieser Ausdruck gut:
("[^"]*"|[^,]+)
Wie im folgenden Beispiel ...
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
Wenn Sie jedoch ein leeres Feld erwarten und Ihr Text relativ klein ist, sollten Sie die leeren Felder vor der Analyse durch ein Leerzeichen ersetzen, um sicherzustellen, dass sie erfasst werden. Zum Beispiel...
...
Set col = rx.Execute(Replace(sText, ",,", ", ,"))
...
Wenn Sie die Integrität der Felder beibehalten möchten, können Sie die Kommas wiederherstellen und Leerzeichen innerhalb der Schleife testen. Dies ist möglicherweise nicht die effizienteste Methode, aber die Arbeit wird erledigt.
Wenn ich den Regex ausprobiere, der von @chubbsondubs auf http://regex101.com mit dem 'g'-Flag gepostet wird, gibt es Übereinstimmungen, die nur', 'oder einen leeren String enthalten.
(?:"([^"]*)"|([^,]*))(?:[,])
Ich kann die Teile des CSV zusammenbringen (einschließlich der zitierten Teile). (Die Zeile muss mit einem ',' abgeschlossen sein, andernfalls wird der letzte Teil nicht erkannt.)
https://regex101.com/r/dF9kQ8/4
Wenn der CSV so aussieht:"",huhu,"hel lo",world,
Es gibt 4 Treffer:
''
'huhu'
'Hallo'
'Welt'
Dies entspricht alles, was ich in c # brauche:
(?<=(^|,)(?<quote>"?))([^"]|(""))*?(?=\<quote>(?=,|$))
Ich hatte eine ähnliche Notwendigkeit, CSV-Werte von SQL-Einfügeanweisungen aufzuteilen.
In meinem Fall konnte ich davon ausgehen, dass Strings in einzelne Anführungszeichen gesetzt wurden und Zahlen nicht.
csv.split(/,((?=')|(?=\d))/g).filter(function(x) { return x !== '';});
Aus irgendeinem offensichtlichen Grund führt diese Regex zu leeren Ergebnissen. Ich könnte diese ignorieren, da leere Werte in meinen Daten als ...,'',...
und nicht als ...,,...
dargestellt wurden.