В регулярном выражении отсутствуют пустые значения? - PullRequest
0 голосов
/ 23 марта 2009
Dim re As New Regex("((?<field>[^"",\r\n]+)|""(?<field>([^""]|"""")+)"")((?<rowbreak>,\r\n|\r\n|\n|$)|,)")


3700,Collin,Franc,,franc@domain.com,Collins,Francine,,franc@domain.com,"Enel North America, Inc.",One T Drive,Suite 220,MyCity,MA,77774,1,traci@domain.com,,,,,3700,
3701,Steur,Larry,,larry@domain.com,Steur,Larry,,larry@domain.com,"St. Petersburg Corp, Inc.",10490 Gady Blvd,,MyCity,FL,33772,1,victor@domain.com,,,,,3701
3705,Giger,Tina,CFO,tina@mydomain.com,Giger,Tina,CFO,tina@mydomain.com,Net Technologies,23 Calab Rd,Suite 202,Calabas,CA,77777,1,Mark@mydomain.com,,,,,3705,

RegEx, который я использую, не работает, потому что если есть пустые столбцы, он «скользит» следующий столбец на свое место. Что я могу сделать, чтобы следующие строки составляли пять столбцов для каждой строки?

1,2,3,4,5
Test,,,Test,
Test,,Test,,

Вот мой полный код:

<%@ Page Language="VB" MasterPageFile="~/_Common/MasterPage.master" %>

<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Text.RegularExpressions" %>
<%@ Import Namespace="System.Xml" %>

<script runat="server">

    Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
    
        ' call the parser
        Dim dt As DataTable = ParseCSVFile(Server.MapPath("Documents/Test.csv"))
    
        ' bind the resulting DataTable to a DataGrid Web Control
        GridView1.DataSource = dt
        GridView1.DataBind()
    End Sub

    Public Function ParseCSV(ByVal inputString As String) As DataTable
    
        Dim dt As New DataTable()
    
        ' declare the Regular Expression that will match versus the input string
        Dim re As New Regex("((?<field>[^"",\r\n]+)|""(?<field>([^""]|"""")+)"")((?<rowbreak>,\r\n|\r\n|\n|$)|,)")
    
        Dim colArray As New ArrayList()
        Dim rowArray As New ArrayList()
    
        Dim colCount As Integer = 0
        Dim maxColCount As Integer = 0
        Dim rowbreak As String = ""
        Dim field As String = ""
    
        Dim mc As MatchCollection = re.Matches(inputString)
    
        For Each m As Match In mc
        
            ' retrieve the field and replace two double-quotes with a single double-quote
            field = m.Result("${field}").Replace("""""", """")
        
            rowbreak = m.Result("${rowbreak}")
        
            If field.Length > 0 Then
                colArray.Add(field)
                colCount += 1
            End If
        
            If rowbreak.Length > 0 Then
            
                ' add the column array to the row Array List
                rowArray.Add(colArray.ToArray())
            
                ' create a new Array List to hold the field values
                colArray = New ArrayList()
            
                If colCount > maxColCount Then
                    maxColCount = colCount
                End If
            
                colCount = 0
            End If
        Next
    
        If rowbreak.Length = 0 Then
            ' this is executed when the last line doesn't
            ' end with a line break
            rowArray.Add(colArray.ToArray())
            If colCount > maxColCount Then
                maxColCount = colCount
            End If
        End If
    
        ' create the columns for the table
        For i As Integer = 0 To maxColCount - 1
            dt.Columns.Add([String].Format("col{0:000}", i))
        Next
    
        ' convert the row Array List into an Array object for easier access
        Dim ra As Array = rowArray.ToArray()
        For i As Integer = 0 To ra.Length - 1
        
            ' create a new DataRow
            Dim dr As DataRow = dt.NewRow()
        
            ' convert the column Array List into an Array object for easier access
            Dim ca As Array = DirectCast((ra.GetValue(i)), Array)
        
            ' add each field into the new DataRow
            For j As Integer = 0 To ca.Length - 1
                dr(j) = ca.GetValue(j)
            Next
        
            ' add the new DataRow to the DataTable
            dt.Rows.Add(dr)
        Next
    
        ' in case no data was parsed, create a single column
        If dt.Columns.Count = 0 Then
            dt.Columns.Add("NoData")
        End If
    
        Return dt
    End Function

    Public Function ParseCSVFile(ByVal path As String) As DataTable
    
        Dim inputString As String = ""
    
        ' check that the file exists before opening it
        If File.Exists(path) Then
        
            Dim sr As New StreamReader(path)
            inputString = sr.ReadToEnd()
            sr.Close()
        
        End If
    
        Return ParseCSV(inputString)
    End Function

</script>


<asp:Content ID="Content1" ContentPlaceHolderID="head" Runat="Server">

</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
    <asp:FileUpload ID="FileUpload1" runat="server" /> 
    <asp:Button ID="btnUpload" runat="server" Text="Upload" />
    <asp:GridView ID="GridView1" runat="server">
    </asp:GridView>
</asp:Content>

На самом деле, я бы предпочел сделать это с Linq, но я не смог найти примеров, в которых использовались файлы CSV с кавычками (для значений, которые содержали запятые в самом значении).

** ОБНОВЛЕНИЕ **

Я изменил RegEx на это, и это приближает меня:

Dim re As New Regex("(?<field>,)|((?<field>[^"",\r\n]+)|""(?<field>([^""]|"""")+)"")(,|(?<rowbreak>\r\n|\n|$))")

теперь он помещает все данные в правильные столбцы, но в пустых столбцах есть только запятая

Ответы [ 2 ]

1 голос
/ 24 марта 2009

Зачем использовать регулярные выражения? У вас довольно простая задача разбора - используйте запятые в качестве разделителей, если они не заключены в кавычки. Таким образом, вы можете перебирать каждую строку символ за символом, устанавливая флаги, когда вы нажимаете противоположную цитату, и сбрасывая ее, когда вы нажимаете конечную цитату. В то время как "внутри цитаты" вы игнорируете запятые. (Я отказался от попыток сделать это с помощью регулярных выражений) ... Попробуйте это:

private DataTable GetDataTableFromCsv(string csvContent)
    {
        DataTable dt = new DataTable();
        string all = csvContent;
        string[] lines = all.Split(new string[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
        foreach (String s in lines)
        {
            bool isInsideQuote = false;
            List<string> values = new List<string>();
            string accumulator = "";
            for (int j = 0; j < s.Length; j++)// (char c in s)
            {
                char c = s[j];
                if (c == '"')
                {
                    if (!isInsideQuote)
                    {
                        isInsideQuote = true;
                    }
                    else
                    {
                        isInsideQuote = false;
                    }
                    accumulator += "\"";
                }
                else if (c == ',' && !isInsideQuote)
                {
                    values.Add(accumulator);
                    accumulator = ""; //reset
                }
                else if (j == s.Length - 1)
                {
                    accumulator += c;
                    values.Add(accumulator);
                    accumulator = "";
                }
                else
                {
                    accumulator += c;
                }
            }
            //first time, create relevant columns
            if (dt.Columns.Count == 0)
            {
                foreach (string colExample in values)
                {
                    dt.Columns.Add();
                }
                //list of strings now contains an example.
            }
            DataRow dr = dt.NewRow();
            for (int i = 0; i < values.Count; i++)
            {
                dr[i] = values[i];
            }
            dt.Rows.Add(dr);
        }
        return dt;
    }
0 голосов
/ 01 сентября 2014

Попробуйте что-то вроде этого: "(?<field1>.*),(?<field2>.*),(?<field3>.*),(?<field4>.*),(?<field5>.*)"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...