none
Reguläre Ausdrücke RRS feed

  • Frage

  • Hallo,

    ich habe eine ; getrennte CSV-Datei. In einigen Zeilen gibt es jedoch manuelle falsch gesetzte Strichpunkte.

    zb: ;999999;;;8888;"Text; Text";10,20;0;0;;;;;; 

    oder ;999999;;;8888;"Text; Text; Text";10,20;0;0;;;;;;

    oder ;999999;;;8888;"Text; Text; ";10,20;0;0;;;;;;

    Die "falschen" Strichpunkte stehen jedoch mmer zwischen 2 Anführungszeichen.

    Welchen regulären Ausdruck müsste ich verwenden bzw. kann man dies mit regulären Ausdrücken lösen.

    Ich würde gerne die Datei in eine Stringvariable lesen, die "falschen" Strichpunkte entfernen und dann die Datei wieder schreiben.

    Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
    
           MsgBox("Start", MsgBoxStyle.Information, "Info")
    
           Dim Vpattern as String = (("[^"]*"))
           Dim Vpattern2 As String = ";"
    
           Dim replacement As String = "§"
    
           Dim rgx As New Regex(Vpattern2)
    
           Dim VFileText() As String = File.ReadAllLines("D:\testen\Alt.csv")
    
           For Each VLine In VFileText
    
                Dim matches As MatchCollection = Regex.Matches(VLine, Vpattern2)
    
                For Each m As Match In matches
                    rgx.Replace(m.Value, replacement)
    
                 Next
    
           End Using
    
           My.Computer.FileSystem.WriteAllText("D:\testen\Neu.csv", VFileText, False)
    
           MsgBox("Ende", MsgBoxStyle.Information, "Info")
    End Sub

    Vielleicht hat ja jemand eine Lösung bzw. einen Lösungsansatz.

    Vielen Dank schon im Voraus dafür.

    Wolfgang


    Donnerstag, 23. Juli 2015 16:35

Antworten

  • Hallo Wolfgang,

    es gibt sicher bessere Wege, das zu tun, hier aber mal eine mögliche Variante:

    Dim Result As String
        Result = "<DerInhaltDerCsvDatei>"
    Dim Matches As MatchCollection
        Matches = Regex.Matches( Result, "\"".*;.*\""", RegexOptions.IgnoreCase Or RegexOptions.Multiline )
    
        For Each Item As Match In Matches
            Result = Result.Replace( Item.Value, Item.Value.Replace( ";", "|||" ) )
        Next
    
        Return Result

    Allerdings sind die Semikola innerhalb der Anführungszeichen nicht falsch. Der Inhalt des Felds ist korrekterweise in doppelte Anführungszeichen eingeschlossen, daher darf der Feldtrenner auch im Wert selbst vorkommen. Die wenigsten Anwendungen haben damit Probleme.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Donnerstag, 23. Juli 2015 17:20
    Moderator
  • Hallo,

    vielen Dank für die schnelle Unterstützung.

    Wie Stefan bereits richtg bemerkt hat, ist nicht mehr praktiabel die komplette Datei in eine String-Variable zu laden, die Ersetzungen zu machen und die Datei zurück zu schreiben.

    Das Programm brauchte ca 20 Sekunden bis es ein paar Ersetzungen (ca 200) durchlaufen hat.

    Mit dem Pattern von Stefan wurden leider auch Stellen ersetzt, die nicht ersetzt werden sollten.

    Ich verwende die nachfolgende Lösung:

    Imports System.Text.RegularExpressions
    Imports System.IO

    Dim VPAT As String = "(" & "(" & """" & "[" & "^" & """" & "]" & "*" & """" & ")" & ")" Dim Result As String

    Dim sr As StreamReader = New StreamReader("D:\testen\alte.csv") Dim wr As StreamWriter = New StreamWriter("D:\testen\neue.csv", False)

    Dim Matches As MatchCollection Do Until sr.Peek() = -1 Result = sr.ReadLine Matches = Regex.Matches(Result, VPAT, RegexOptions.IgnoreCase Or RegexOptions.Multiline) For Each Item As Match In Matches Result = Result.Replace(Item.Value, Item.Value.Replace(";", ":")) Next wr.WriteLine(Result) Loop sr.Close() wr.Close()

    Mit dem Pattern in der Variable VPAT werden alle Stellen gefunden, wo Zeichen zwischen Anführungszeichen stehen.

    Vielen Dank noch einmal an Stefan. Du hast mich auf den richtigen Weg gebracht.

    Besten Grüßen

    Wolfgang

    Freitag, 24. Juli 2015 13:32

Alle Antworten

  • Hallo Wolfgang,

    es gibt sicher bessere Wege, das zu tun, hier aber mal eine mögliche Variante:

    Dim Result As String
        Result = "<DerInhaltDerCsvDatei>"
    Dim Matches As MatchCollection
        Matches = Regex.Matches( Result, "\"".*;.*\""", RegexOptions.IgnoreCase Or RegexOptions.Multiline )
    
        For Each Item As Match In Matches
            Result = Result.Replace( Item.Value, Item.Value.Replace( ";", "|||" ) )
        Next
    
        Return Result

    Allerdings sind die Semikola innerhalb der Anführungszeichen nicht falsch. Der Inhalt des Felds ist korrekterweise in doppelte Anführungszeichen eingeschlossen, daher darf der Feldtrenner auch im Wert selbst vorkommen. Die wenigsten Anwendungen haben damit Probleme.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Donnerstag, 23. Juli 2015 17:20
    Moderator
  • Hallo Stefan,

    vielen Dank für die schnelle Antwort. Ich habe versucht deine Lösung zu verwenden.

    Leider fliegt mir das Programm dabei auf das Näschen:

    Zusätzliche Informationen: Die CLR konnte 60 Sekunden lang keinen Übergang vom COM-Kontext 0x149ffa0 zum COM-Kontext 0x14a0058 durchführen.

    Vielleicht habe ich vor lauter Probieren doch noch etwas übersehen?

    Die "falschen" Strichpunkte werden von Mitarbeitern eingeben, die im Textfeld mit Caps Lock schreiben.

    Die Datei hat ca. 60.000 Zeilen und muss tgl. neu ins DWH per BULK-Insert verarbeitet werden.

    MsgBox("Start", MsgBoxStyle.Information, "no nicht getan")
    
    
    Dim Result As String
    
    Result = My.Computer.FileSystem.ReadAllText("D:\testen\alte.csv")
    
    Dim Matches As MatchCollection
    
    Matches = Regex.Matches(Result, "\"".*;.*\""", RegexOptions.IgnoreCase Or RegexOptions.Multiline)
    
    
    For Each Item As Match In Matches
    
        Result = Result.Replace(Item.Value, Item.Value.Replace(";", "|||"))
    
    Next
    
    
    My.Computer.FileSystem.WriteAllText("D:\testen\Neu.csv", Result, False)
    

    Donnerstag, 23. Juli 2015 17:58
  • Hallo Wolfgang,

    Dein Programm läuft im Debug-Modus? Probier es mal ohne Debug-Modus.

    Ich tippe mal darauf dass die GUI zu lange blockiert wird. Hier könnte eine Auslagerung der Funktion in einen eigenen Thread evtl. helfen.

    Besten Gruß

    Freitag, 24. Juli 2015 09:55
  • Hallo Wolfgang,

    bei so vielen Zeilen ist eine normale Stringersetzung nicht mehr praktikabel, da das intern zu viele Ressourcen verbrät.

    Daher hier eine Variante mit einem StringBuilder, die sollte problemlos laufen.

    Dim SB      As New StringBuilder()
    Dim Matches As MatchCollection
        Matches = Regex.Matches( Value, "(.*)(\"".*;.*\"")(.*)", RegexOptions.IgnoreCase Or RegexOptions.Multiline )
    
        For Each Item As Match In Matches
            SB.Append( Item.Groups( 1 ).Value & Item.Groups( 2 ).Value.Replace( ";", "|||" ) & Item.Groups( 3 ).Value )
        Next
    
        Return SB.ToString()
    


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Freitag, 24. Juli 2015 11:06
    Moderator
  • Hallo,

    vielen Dank für die schnelle Unterstützung.

    Wie Stefan bereits richtg bemerkt hat, ist nicht mehr praktiabel die komplette Datei in eine String-Variable zu laden, die Ersetzungen zu machen und die Datei zurück zu schreiben.

    Das Programm brauchte ca 20 Sekunden bis es ein paar Ersetzungen (ca 200) durchlaufen hat.

    Mit dem Pattern von Stefan wurden leider auch Stellen ersetzt, die nicht ersetzt werden sollten.

    Ich verwende die nachfolgende Lösung:

    Imports System.Text.RegularExpressions
    Imports System.IO

    Dim VPAT As String = "(" & "(" & """" & "[" & "^" & """" & "]" & "*" & """" & ")" & ")" Dim Result As String

    Dim sr As StreamReader = New StreamReader("D:\testen\alte.csv") Dim wr As StreamWriter = New StreamWriter("D:\testen\neue.csv", False)

    Dim Matches As MatchCollection Do Until sr.Peek() = -1 Result = sr.ReadLine Matches = Regex.Matches(Result, VPAT, RegexOptions.IgnoreCase Or RegexOptions.Multiline) For Each Item As Match In Matches Result = Result.Replace(Item.Value, Item.Value.Replace(";", ":")) Next wr.WriteLine(Result) Loop sr.Close() wr.Close()

    Mit dem Pattern in der Variable VPAT werden alle Stellen gefunden, wo Zeichen zwischen Anführungszeichen stehen.

    Vielen Dank noch einmal an Stefan. Du hast mich auf den richtigen Weg gebracht.

    Besten Grüßen

    Wolfgang

    Freitag, 24. Juli 2015 13:32
  • Hallo Wolfgang,

    probier aber doch nochmal die Variante mit dem StringBuilder, die ist erheblich schneller.

    Wenn Du uns verrätst, welche Probleme noch bei den Ersetzungen bestehen, kann man den Regex Ausdruck sicher noch anpassen.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Freitag, 24. Juli 2015 13:42
    Moderator