Xử lý dấu phẩy trong tệp CSV


472

Tôi đang tìm kiếm đề xuất về cách xử lý tệp csv đang được tạo, sau đó được khách hàng của chúng tôi tải lên và có thể có dấu phẩy trong một giá trị, như tên công ty.

Một số ý tưởng chúng tôi đang xem xét là: Số định danh được trích dẫn (giá trị "," giá trị "," vv) hoặc sử dụng một | thay vì dấu phẩy. Vấn đề lớn nhất là chúng ta phải làm cho nó dễ dàng, hoặc khách hàng sẽ không làm điều đó.


khách hàng đang viết nó và tải nó lên
Bob The Janitor

1
Đây là giải pháp để quản lý bên trong dấu phẩy trong tệp csv. truy cập stackoverflow.com/questions/9889225/ từ
Hasan Abrar

trên iOS, về cơ bản, bạn phải sử dụng github.com/Flinesoft/CSVImporter
Fattie

3
Lưu ý rằng QA này là cũ. Ngày nay csv có nghĩa là RFC 4180 và đó là điều đó.
Fattie

Tôi có cùng một vấn đề, cố gắng tổng cộng một cột trong tệp csv được phân tách bằng dấu phẩy. Không có vấn đề với một lệnh awk. Thật không may, một số ô có thể chứa dấu phẩy (ví dụ trong một địa chỉ), các ô khác sẽ không. Tìm kiếm một giải pháp tương thích với Linux nhưng không biết bắt đầu từ đâu.
cây xanh

Câu trả lời:


223

Như những người khác đã nói, bạn cần phải thoát khỏi các giá trị bao gồm dấu ngoặc kép. Đây là một trình đọc CSV nhỏ trong C♯ hỗ trợ các giá trị được trích dẫn, bao gồm các trích dẫn được nhúng và trả về vận chuyển.

Nhân tiện, đây là mã thử nghiệm đơn vị. Tôi đang đăng nó ngay bây giờ vì câu hỏi này dường như xuất hiện rất nhiều và những người khác có thể không muốn toàn bộ thư viện khi hỗ trợ CSV đơn giản sẽ làm.

Bạn có thể sử dụng nó như sau:

using System;
public class test
{
    public static void Main()
    {
        using ( CsvReader reader = new CsvReader( "data.csv" ) )
        {
            foreach( string[] values in reader.RowEnumerator )
            {
                Console.WriteLine( "Row {0} has {1} values.", reader.RowIndex, values.Length );
            }
        }
        Console.ReadLine();
    }
}

Dưới đây là các lớp học. Lưu ý rằng bạn cũng có thể sử dụng Csv.Escapechức năng để viết CSV hợp lệ.

using System.IO;
using System.Text.RegularExpressions;

public sealed class CsvReader : System.IDisposable
{
    public CsvReader( string fileName ) : this( new FileStream( fileName, FileMode.Open, FileAccess.Read ) )
    {
    }

    public CsvReader( Stream stream )
    {
        __reader = new StreamReader( stream );
    }

    public System.Collections.IEnumerable RowEnumerator
    {
        get {
            if ( null == __reader )
                throw new System.ApplicationException( "I can't start reading without CSV input." );

            __rowno = 0;
            string sLine;
            string sNextLine;

            while ( null != ( sLine = __reader.ReadLine() ) )
            {
                while ( rexRunOnLine.IsMatch( sLine ) && null != ( sNextLine = __reader.ReadLine() ) )
                    sLine += "\n" + sNextLine;

                __rowno++;
                string[] values = rexCsvSplitter.Split( sLine );

                for ( int i = 0; i < values.Length; i++ )
                    values[i] = Csv.Unescape( values[i] );

                yield return values;
            }

            __reader.Close();
        }
    }

    public long RowIndex { get { return __rowno; } }

    public void Dispose()
    {
        if ( null != __reader ) __reader.Dispose();
    }

    //============================================


    private long __rowno = 0;
    private TextReader __reader;
    private static Regex rexCsvSplitter = new Regex( @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))" );
    private static Regex rexRunOnLine = new Regex( @"^[^""]*(?:""[^""]*""[^""]*)*""[^""]*$" );
}

public static class Csv
{
    public static string Escape( string s )
    {
        if ( s.Contains( QUOTE ) )
            s = s.Replace( QUOTE, ESCAPED_QUOTE );

        if ( s.IndexOfAny( CHARACTERS_THAT_MUST_BE_QUOTED ) > -1 )
            s = QUOTE + s + QUOTE;

        return s;
    }

    public static string Unescape( string s )
    {
        if ( s.StartsWith( QUOTE ) && s.EndsWith( QUOTE ) )
        {
            s = s.Substring( 1, s.Length - 2 );

            if ( s.Contains( ESCAPED_QUOTE ) )
                s = s.Replace( ESCAPED_QUOTE, QUOTE );
        }

        return s;
    }


    private const string QUOTE = "\"";
    private const string ESCAPED_QUOTE = "\"\"";
    private static char[] CHARACTERS_THAT_MUST_BE_QUOTED = { ',', '"', '\n' };
}

2
Bạn cũng có thể cần dịch \ r \ n để tuân thủ windows, tùy thuộc vào ứng dụng của bạn.
Mandrake

3
@NadaNaeem, quan tâm đến công phu?
harpo 7/07/2015

nó không đếm chính xác các mục trong một hàng tệp csv, nó không xử lý tốt các dấu phẩy trong các trường và trả lại can đảm và vòi
Nada N. Hantouli

-1 OP không chỉ định ngôn ngữ tạo tệp. Nếu bất kỳ lập trình viên nào khác đến đây để tìm giải pháp bằng bất kỳ ngôn ngữ nào ngoài C #, họ sẽ không tìm thấy giải pháp họ có thể sử dụng trong câu trả lời này.
Ben Leggiero

8
@ BenC.R.Leggiero, sau đó tôi cho rằng bạn cũng phải đánh giá thấp câu hỏi, vì nó không thể trả lời được theo tiêu chuẩn của bạn. Như vậy, mã này là một triển khai chính thức của một thông số kỹ thuật đơn giản và có thể dễ dàng được dịch sang bất kỳ ngôn ngữ thường sử dụng nào.
harpo

395

Đối với năm 2017, csv được chỉ định đầy đủ - RFC 4180.

Đây là một đặc điểm kỹ thuật rất phổ biến và được bao phủ hoàn toàn bởi nhiều thư viện ( ví dụ ).

Đơn giản chỉ cần sử dụng bất kỳ thư viện csv có sẵn dễ dàng - có nghĩa là RFC 4180.


Thực sự có một thông số cho định dạng CSV và cách xử lý dấu phẩy:

Các trường có chứa dấu ngắt dòng (CRLF), dấu ngoặc kép và dấu phẩy phải được đặt trong dấu ngoặc kép.

http://tools.ietf.org/html/rfc4180

Vì vậy, để có giá trị foobar,baz, bạn làm điều này:

foo,"bar,baz"

Một yêu cầu quan trọng khác để xem xét (cũng từ thông số kỹ thuật):

Nếu dấu ngoặc kép được sử dụng để bao quanh các trường, thì dấu ngoặc kép xuất hiện bên trong một trường phải được thoát bằng cách đặt trước nó bằng dấu ngoặc kép khác. Ví dụ:

"aaa","b""bb","ccc"

120
"Các trường có chứa ngắt dòng (CRLF), dấu ngoặc kép và dấu phẩy nên được đặt trong dấu ngoặc kép."
Eli

42
"Nếu trích dẫn kép được sử dụng để bao quanh các trường, thì một trích dẫn kép xuất hiện bên trong một trường phải được thoát bằng cách đặt trước nó bằng một trích dẫn kép khác."
C. Rồng 76

11
Không thực sự là một thông số kỹ thuật, nhưng vẫn có thể tiện dụng. Nó nói ... "Không có thông số kỹ thuật chính thức nào tồn tại, cho phép thực hiện nhiều cách hiểu khác nhau về các tệp CSV. Phần này ghi lại định dạng dường như được tuân theo bởi hầu hết các triển khai."
Justin Clarke

5
Ngoài ra, đừng quên rằng, mặc dù tên của nó, các giá trị CSV trong hàng có thể được phân tách không chỉ bằng dấu phẩy - ít nhất là trên các nền tảng Windows. Nó phụ thuộc vào các cài đặt khu vực hiện tại (intl.cpl trong dòng lệnh, "Cài đặt nâng cao"), đặc biệt, phân tách danh sách : System.Globalization.CultureInfo.CurrentCulture.TextInfo.ListSeparator.
lxa

4
Vui lòng đặt thông tin liên quan vào câu trả lời này, ngoài liên kết, đến A) Xóa hầu hết các ý kiến ​​trên (và của tôi), B) Lưu rất nhiều người hơn người trả lời thời gian để đi đến một trang khác và tìm thấy liên quan dữ liệu, C) Ngăn chặn Liên kết Rot.
user66001

76

Định dạng CSV sử dụng dấu phẩy để phân tách các giá trị, giá trị chứa lợi nhuận vận chuyển, nguồn cấp dữ liệu, dấu phẩy hoặc dấu ngoặc kép được bao quanh bởi dấu ngoặc kép. Các giá trị có chứa dấu ngoặc kép được trích dẫn và mỗi trích dẫn bằng chữ được thoát bằng một trích dẫn ngay trước đó: Ví dụ: 3 giá trị:

test
list, of, items
"go" he said

sẽ được mã hóa thành:

test
"list, of, items"
"""go"" he said"

Bất kỳ trường nào cũng có thể được trích dẫn nhưng chỉ các trường có dấu phẩy, CR / NL hoặc dấu ngoặc kép phải được trích dẫn.

Không có tiêu chuẩn thực sự cho định dạng CSV, nhưng hầu như tất cả các ứng dụng đều tuân theo các quy ước được ghi lại ở đây . RFC được đề cập ở nơi khác không phải là tiêu chuẩn cho CSV, nó là RFC để sử dụng CSV trong MIME và chứa một số hạn chế không cần thiết và không cần thiết khiến nó trở nên vô dụng bên ngoài MIME.

Một hình ảnh xác thực mà nhiều mô-đun CSV tôi đã thấy không phù hợp là thực tế là nhiều dòng có thể được mã hóa trong một trường duy nhất, điều đó có nghĩa là bạn không thể cho rằng mỗi dòng là một bản ghi riêng biệt, bạn không cần phải cho phép dòng mới trong dữ liệu hoặc được chuẩn bị để xử lý này.


40

Đặt dấu ngoặc kép quanh chuỗi. Đó thường là những gì Excel làm .

Ala Eli,

bạn thoát khỏi một trích dẫn kép như hai dấu ngoặc kép. Ví dụ: "test1", "foo" "bar", "test2"


về cơ bản là khái niệm tương tự như một Định danh được trích dẫn
Bob The Janitor

1
bạn thoát khỏi một trích dẫn kép như hai dấu ngoặc kép. Ví dụ: "test1", "foo" "bar", "test2"
Eli

Chỉ đặt dấu ngoặc kép quanh chuỗi không hoạt động khi dấu "được theo dõi ngay sau dấu phẩy
MondKin

9

Bạn có thể đặt dấu ngoặc kép xung quanh các lĩnh vực. Tôi không thích cách tiếp cận này, vì nó thêm một ký tự đặc biệt khác (trích dẫn kép). Chỉ cần xác định một ký tự thoát (thường là dấu gạch chéo ngược) và sử dụng nó bất cứ nơi nào bạn cần để thoát một cái gì đó:

dữ liệu, nhiều dữ liệu hơn, nhiều dữ liệu hơn \, thậm chí, nhưng nhiều hơn nữa

Bạn không phải cố gắng khớp các trích dẫn và bạn có ít ngoại lệ hơn để phân tích cú pháp. Điều này cũng đơn giản hóa mã của bạn.


3
Nhanh và bẩn nhưng không hoạt động nếu bạn thực sự có một mục có chứa "\,"
Sarp Kaya

1
Sarp, đó là lý do tại sao một đôi \ là một dấu gạch chéo ngược thoát, vì bây giờ nó trở thành một ký tự đặc biệt khác.
Grungondola

1
Điều này hoạt động, nhưng không phải là CSV. Đó là DSV .
TRiG

8

Có một thư viện có sẵn thông qua nuget để xử lý khá nhiều CSV (.net) được hình thành tốt - CsvHelper

Ví dụ để ánh xạ tới một lớp:

var csv = new CsvReader( textReader );
var records = csv.GetRecords<MyClass>();

Ví dụ để đọc các trường riêng lẻ:

var csv = new CsvReader( textReader );
while( csv.Read() )
{
    var intField = csv.GetField<int>( 0 );
    var stringField = csv.GetField<string>( 1 );
    var boolField = csv.GetField<bool>( "HeaderName" );
}

Để máy khách điều khiển định dạng tệp:
, là dấu phân cách trường tiêu chuẩn, "là giá trị tiêu chuẩn được sử dụng để thoát các trường có chứa dấu phân cách, trích dẫn hoặc kết thúc dòng.

Để sử dụng (ví dụ) #cho các trường và 'để thoát:

var csv = new CsvReader( textReader );
csv.Configuration.Delimiter = "#";
csv.Configuration.Quote = ''';
// read the file however meets your needs

Thêm tài liệu


3
Sẽ tốt hơn nếu bạn đưa vào một ví dụ về cách sử dụng CsvHelperthư viện để giải quyết vấn đề của OP.
George Stocker

Tại sao gần như mọi thứ trong .Net phải là "Người trợ giúp" ... từ này gần như vô nghĩa ... như "Người quản lý".
bytedev

5

Như đã đề cập trong nhận xét của tôi về câu trả lời của harpo, giải pháp của anh ấy rất tốt và hoạt động trong hầu hết các trường hợp, tuy nhiên trong một số trường hợp khi các dấu phẩy tiếp giáp trực tiếp với nhau thì không thể phân tách trên dấu phẩy.

Điều này là do chuỗi Regex hoạt động bất ngờ như một chuỗi vertabim. Để có được hành vi này chính xác, tất cả "các ký tự trong chuỗi regex cần phải được thoát thủ công mà không cần sử dụng thoát vertabim.

I E. Regex nên được sử dụng thoát thủ công:

",(?=(?:[^\"\"]*\"\"[^\"\"]*\"\")*(?![^\"\"]*\"\"))"

mà chuyển thành ",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"

Khi sử dụng chuỗi vertabim, @",(?=(?:[^""]*""[^""]*"")*(?![^""]*""))"nó hoạt động như sau như bạn có thể thấy nếu bạn gỡ lỗi regex:

",(?=(?:[^"]*"[^"]*")*(?![^"]*"))"

Vì vậy, tóm lại, tôi khuyên bạn nên sử dụng giải pháp của harpo, nhưng hãy coi chừng chú chó nhỏ này!

Tôi đã đưa vào CsvReader một chút không an toàn tùy chọn để thông báo cho bạn nếu lỗi này xảy ra (nếu bạn có số lượng cột được biết trước):

if (_expectedDataLength > 0 && values.Length != _expectedDataLength) 
throw new DataLengthException(string.Format("Expected {0} columns when splitting csv, got {1}", _expectedDataLength, values.Length));

Điều này có thể được tiêm thông qua các nhà xây dựng:

public CsvReader(string fileName, int expectedDataLength = 0) : this(new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
    _expectedDataLength = expectedDataLength;
}

Làm thế nào bạn sẽ đi về việc xử lý hàng Header? Tôi đang cố gắng ánh xạ các đối tượng csv sang C # là tất cả các loại, nhưng hàng tiêu đề phá vỡ nó vì tất cả các chuỗi của nó ...
tCoe

Không [^""]giống như [^"]? Sao chép một ký tự bên trong một đặc tả lớp nhân vật là dư thừa, phải không?
Minh Trần

4

Thêm một tham chiếu đến Microsoft.VisualBasic (vâng, nó nói VisualBasic nhưng nó cũng hoạt động trong C # - hãy nhớ rằng cuối cùng tất cả chỉ là IL).

Sử dụng Microsoft.VisualBasic.FileIO.TextFieldParserlớp để phân tích tệp CSV Đây là mã mẫu:

 Dim parser As TextFieldParser = New TextFieldParser("C:\mar0112.csv")
 parser.TextFieldType = FieldType.Delimited
 parser.SetDelimiters(",")      

   While Not parser.EndOfData         
      'Processing row             
      Dim fields() As String = parser.ReadFields         
      For Each field As String In fields             
         'TODO: Process field                   

      Next      
      parser.Close()
   End While 

Vâng, đây là một lớp rất hữu ích trong một không gian tên hơi đáng tiếc ;-). Tuy nhiên, để giải quyết câu hỏi ban đầu, bạn cũng nên cài đặt parser.HasFieldsEnclosedInQuotes = true;và tệp đầu vào sẽ cần kèm theo các trường có dấu phẩy trong dấu ngoặc kép theo thông số CSV - excel đã thực hiện điều này.
Christopher King


4

Trong trường hợp bạn đang ở trên một * nix-hệ thống , có thể truy cập sedvà có thể có một hoặc nhiều không mong muốn dấu phẩy chỉ trong một lĩnh vực cụ thể của CSV của bạn, bạn có thể sử dụng sau một lót để khép kín chúng trong "khi RFC4180 Mục 2 đề xuất:

sed -r 's/([^,]*,[^,]*,[^,]*,)(.*)(,.*,.*)/\1"\2"\3/' inputfile

Tùy thuộc vào trường nào, dấu phẩy không mong muốn có thể nằm trong bạn phải thay đổi / mở rộng các nhóm bắt giữ của biểu thức chính quy (và thay thế).
Ví dụ trên sẽ bao gồm trường thứ tư (trong số sáu) trong dấu ngoặc kép.

nhập mô tả hình ảnh ở đây

Kết hợp với --in-place-option, bạn có thể áp dụng những thay đổi này trực tiếp vào tệp.

Để "xây dựng" regex đúng, có một nguyên tắc đơn giản cần tuân thủ:

  1. Đối với mọi trường trong CSV của bạn xuất hiện trước trường có dấu phẩy không mong muốn, bạn viết một trường [^,]*,và đặt tất cả chúng lại với nhau trong một nhóm bắt giữ.
  2. Đối với trường có chứa dấu phẩy không mong muốn bạn viết (.*).
  3. Đối với mọi trường sau trường có dấu phẩy không mong muốn, bạn viết một ,.* và đặt tất cả chúng lại với nhau trong một nhóm bắt giữ.

Dưới đây là một tổng quan ngắn về các biểu thức / thay thế có thể khác nhau tùy thuộc vào lĩnh vực cụ thể. Nếu không được đưa ra, sự thay thế là \1"\2"\3.

([^,]*)(,.*)                     #first field, regex
"\1"\2                           #first field, substitution

(.*,)([^,]*)                     #last field, regex
\1"\2"                           #last field, substitution


([^,]*,)(.*)(,.*,.*,.*)          #second field (out of five fields)
([^,]*,[^,]*,)(.*)(,.*)          #third field (out of four fields)
([^,]*,[^,]*,[^,]*,)(.*)(,.*,.*) #fourth field (out of six fields)

Nếu bạn muốn xóa (các) dấu phẩy không mong muốn bằng sedthay vì kèm theo chúng bằng dấu ngoặc kép, hãy tham khảo câu trả lời này .


3

Nếu bạn cảm thấy muốn phát minh lại bánh xe, những điều sau đây có thể phù hợp với bạn:

public static IEnumerable<string> SplitCSV(string line)
{
    var s = new StringBuilder();
    bool escaped = false, inQuotes = false;
    foreach (char c in line)
    {
        if (c == ',' && !inQuotes)
        {
            yield return s.ToString();
            s.Clear();
        }
        else if (c == '\\' && !escaped)
        {
            escaped = true;
        }
        else if (c == '"' && !escaped)
        {
            inQuotes = !inQuotes;
        }
        else
        {
            escaped = false;
            s.Append(c);
        }
    }
    yield return s.ToString();
}

3

Ở châu Âu chúng ta có vấn đề này phải sớm hơn câu hỏi này. Ở châu Âu, chúng tôi sử dụng tất cả dấu phẩy cho dấu thập phân. Xem số này dưới đây:

| American      | Europe        |
| ------------- | ------------- |
| 0.5           | 0,5           |
| 3.14159265359 | 3,14159265359 |
| 17.54         | 17,54         |
| 175,186.15    | 175.186,15    |

Vì vậy, không thể sử dụng dấu tách dấu phẩy cho các tệp CSV. Vì lý do đó, các tệp CSV ở Châu Âu được phân tách bằng dấu chấm phẩy ( ;) .

Các chương trình như Microsoft Excel có thể đọc các tệp bằng dấu chấm phẩy và có thể chuyển từ dấu phân cách. Bạn thậm chí có thể sử dụng một tab ( \t) làm dấu phân cách. Xem câu trả lời này từ Supper User .


2

Nếu bạn quan tâm đến một bài tập giáo dục nhiều hơn về cách phân tích các tệp nói chung (sử dụng CSV làm ví dụ), bạn có thể xem bài viết này của Julian Bucknall. Tôi thích bài viết vì nó chia mọi thứ thành những vấn đề nhỏ hơn nhiều mà không thể vượt qua. Trước tiên, bạn tạo một ngữ pháp và một khi bạn có một ngữ pháp tốt, đó là một quá trình tương đối dễ dàng và có phương pháp để chuyển đổi ngữ pháp thành mã.

Bài viết sử dụng C # và có một liên kết ở phía dưới để tải mã.


1

Đây là một cách giải quyết nhỏ gọn:

Thay vào đó, bạn có thể sử dụng Dấu số thấp hơn của Hy Lạp (U + 0375)

Có vẻ như thế này

Sử dụng phương pháp này cũng giúp bạn tiết kiệm rất nhiều tài nguyên ...


1

Chỉ cần sử dụng SoftCircuits.CsvParser trên NuGet. Nó sẽ xử lý tất cả các chi tiết đó cho bạn và xử lý hiệu quả các tệp rất lớn. Và, nếu cần, nó thậm chí có thể nhập / xuất đối tượng bằng cách ánh xạ các cột vào thuộc tính đối tượng. Ngoài ra, thử nghiệm của tôi cho thấy nó trung bình nhanh hơn gần 4 lần so với CsvHelper phổ biến.


0

Vì đây là về thực tiễn chung, hãy bắt đầu từ quy tắc của ngón tay cái:

  1. Không sử dụng CSV, thay vào đó hãy sử dụng XML với thư viện để đọc và ghi tệp xml.

  2. Nếu bạn phải sử dụng CSV. Làm điều đó đúng cách và sử dụng một thư viện miễn phí để phân tích và lưu trữ các tệp CSV.

Để biện minh cho 1), hầu hết các trình phân tích cú pháp CSV không mã hóa nhận thức vì vậy nếu bạn không giao dịch với US-ASCII, bạn sẽ yêu cầu sự cố. Ví dụ excel 2002 đang lưu trữ CSV trong mã hóa cục bộ mà không có bất kỳ lưu ý nào về mã hóa. Tiêu chuẩn CSV không được áp dụng rộng rãi :(. Mặt khác, tiêu chuẩn xml được chấp nhận tốt và nó xử lý mã hóa khá tốt.

Để biện minh cho 2), có hàng tấn trình phân tích cú pháp csv xung quanh cho hầu hết tất cả các ngôn ngữ, do đó không cần phải phát minh lại bánh xe ngay cả khi các giải pháp có vẻ khá đơn giản.

Để tên

  • cho python sử dụng xây dựng trong mô-đun csv

  • để kiểm tra perl CPAN và văn bản :: CSV

  • cho php sử dụng build trong các hàm fgetcsv / fputcsv

  • cho java kiểm tra thư viện SuperCVS

Thực sự không cần phải thực hiện điều này bằng tay nếu bạn sẽ không phân tích cú pháp trên thiết bị nhúng.


12
XML không phải lúc nào cũng là câu trả lời. CSV là định dạng phù hợp cho công việc khi bạn có nhiều dữ liệu dạng bảng dày đặc (ví dụ: bảng tính). Các thẻ đó giới thiệu rất nhiều chi phí và nếu mỗi dòng có một định dạng giống hệt nhau, thì không cần phải rõ ràng về những gì mỗi và mọi giá trị đại diện. XML thật tuyệt vời khi bạn có dữ liệu phân cấp phức tạp hoặc các bản ghi với các trường tùy chọn. Đó không phải là luôn luôn như vậy.
Adam Jaskiewicz

Về lý thuyết, các "thẻ" giới thiệu một chút chi phí nhưng tôi không thể nghĩ ra bất kỳ ứng dụng thực tế nào khi nó bắt đầu là một vấn đề. Bạn có bất kỳ ví dụ thực tế? Để làm việc trên dữ liệu người ta nên sử dụng cơ sở dữ liệu thay vì csv. Nếu chúng ta nói về tuần tự hóa dữ liệu (sao lưu, trao đổi dữ liệu), sẽ có vấn đề gì nếu phân tích cú pháp mất một tuần thay vì 5 ngày?
Piotr Czapla

2
Về cơ bản, bất kỳ tình huống nào bạn có dữ liệu được biểu thị tốt nhất bằng bảng. Giả sử bạn có dữ liệu từ hàng tá cảm biến khác nhau mà bạn thường xuyên lấy mẫu và bạn ghi lại dấu thời gian và giá trị của từng cảm biến tại thời điểm đó. Mỗi bản ghi giống hệt nhau: dấu thời gian, cảm biến0, cảm biến1, ... cảm biến11. XML là tuyệt vời để biểu diễn dữ liệu phức tạp, bất thường, nhưng nó là một định dạng khá nặng không phù hợp với mọi tình huống. KISS
Adam Jaskiewicz

10
Một số người nhìn thấy một vấn đề và họ nói "Tôi biết, tôi sẽ sử dụng XML!" Bây giờ họ có hai vấn đề.
Adam Jaskiewicz

Tôi hoàn toàn đồng ý rằng xml không phải là câu trả lời cho mọi thứ. Đặc biệt nó không phù hợp như là một sự thay thế cơ sở dữ liệu cũng như cho các tập tin cấu hình. Nhưng ở đây câu hỏi là về trao đổi dữ liệu mà XML được thiết kế cho.
Piotr Czapla

0

Bạn có thể đọc tệp csv như thế này.

điều này làm cho việc sử dụng các phần tách và chăm sóc không gian.

ArrayList List = new ArrayList();
static ServerSocket Server;
static Socket socket;
static ArrayList<Object> list = new ArrayList<Object>();


public static void ReadFromXcel() throws FileNotFoundException
{   
    File f = new File("Book.csv");
    Scanner in = new Scanner(f);
    int count  =0;
    String[] date;
    String[] name;
    String[] Temp = new String[10];
    String[] Temp2 = new String[10];
    String[] numbers;
    ArrayList<String[]> List = new ArrayList<String[]>();
    HashMap m = new HashMap();

         in.nextLine();
         date = in.nextLine().split(",");
         name = in.nextLine().split(",");
         numbers = in.nextLine().split(",");
         while(in.hasNext())
         {
             String[] one = in.nextLine().split(",");
             List.add(one);
         }
         int xount = 0;
         //Making sure the lines don't start with a blank
         for(int y = 0; y<= date.length-1; y++)
         {
             if(!date[y].equals(""))
             {   
                 Temp[xount] = date[y];
                 Temp2[xount] = name[y];
                 xount++;
             }
         }

         date = Temp;
         name =Temp2;
         int counter = 0;
         while(counter < List.size())
         {
             String[] list = List.get(counter);
             String sNo = list[0];
             String Surname = list[1];
             String Name = list[2];
             for(int x = 3; x < list.length; x++)
             {           
                 m.put(numbers[x], list[x]);
             }
            Object newOne = new newOne(sNo, Name, Surname, m, false);
             StudentList.add(s);
             System.out.println(s.sNo);
             counter++;
         }

0

Trước tiên, hãy tự hỏi: "Tại sao chúng ta cảm thấy cần phải xử lý dấu phẩy khác nhau cho các tệp CSV?"

Đối với tôi, câu trả lời là "Bởi vì khi tôi xuất dữ liệu thành tệp CSV, dấu phẩy trong trường sẽ biến mất và trường của tôi được tách thành nhiều trường trong đó dấu phẩy xuất hiện trong dữ liệu gốc." (Đó là vì dấu phẩy là ký tự phân tách trường CSV.)

Tùy thuộc vào tình huống của bạn, dấu chấm phẩy cũng có thể được sử dụng làm dấu tách trường CSV.

Đưa ra yêu cầu của tôi, tôi có thể sử dụng một ký tự, ví dụ: dấu ngoặc kép thấp 9, trông giống như dấu phẩy.

Vì vậy, đây là cách bạn có thể làm điều đó trong Go:

// Replace special CSV characters with single low-9 quotation mark
func Scrub(a interface{}) string {
    s := fmt.Sprint(a)
    s = strings.Replace(s, ",", "‚", -1)
    s = strings.Replace(s, ";", "‚", -1)
    return s
}

Ký tự dấu phẩy thứ hai trong hàm Thay thế là số thập phân 8218.

Xin lưu ý rằng nếu bạn có các máy khách có thể có trình đọc văn bản chỉ có ascii thì ký tự decima 8218 này sẽ không giống như dấu phẩy. Nếu đây là trường hợp của bạn, thì tôi khuyên bạn nên bao quanh trường bằng dấu phẩy (hoặc dấu chấm phẩy) với dấu ngoặc kép cho mỗi RFC 4128: https://tools.ietf.org/html/rfc4180


0

Tôi thường mã hóa URL các trường có thể có bất kỳ dấu phẩy hoặc bất kỳ ký tự đặc biệt nào. Và sau đó giải mã nó khi nó đang được sử dụng / hiển thị trong bất kỳ phương tiện trực quan nào.

(dấu phẩy trở thành% 2C)

Mỗi ngôn ngữ nên có các phương thức để mã hóa URL và giải mã chuỗi.

ví dụ: trong java

URLEncoder.encode(myString,"UTF-8"); //to encode
URLDecoder.decode(myEncodedstring, "UTF-8"); //to decode

Tôi biết đây là một giải pháp rất chung chung và nó có thể không lý tưởng cho trường hợp người dùng muốn xem nội dung của tệp csv theo cách thủ công.


0

Tôi thường làm điều này trong các thói quen phân tích cú pháp tệp CSV của tôi. Giả sử rằng biến 'dòng' là một dòng trong tệp CSV và tất cả các giá trị của cột được đặt trong dấu ngoặc kép. Sau khi hai dòng dưới đây thực thi, bạn sẽ nhận được các cột CSV trong bộ sưu tập 'giá trị'.

// The below two lines will split the columns as well as trim the DBOULE QUOTES around values but NOT within them
    string trimmedLine = line.Trim(new char[] { '\"' });
    List<string> values = trimmedLine.Split(new string[] { "\",\"" }, StringSplitOptions.None).ToList();

1
Tại sao mã của tôi không bao giờ được hiển thị trong nhiều màu trên StackOverflow? Tôi thụt lề bởi bốn không gian.
user1451111


0

Giải pháp đơn giản nhất mà tôi đã tìm thấy là một LibreScript sử dụng:

  1. Thay thế tất cả "bằng chữ
  2. Đặt dấu ngoặc kép quanh chuỗi của bạn

Bạn cũng có thể sử dụng cái mà Excel sử dụng:

  1. Thay thế tất cả "bằng chữ""
  2. Đặt dấu ngoặc kép quanh chuỗi của bạn

Lưu ý những người khác được khuyến nghị chỉ thực hiện bước 2 ở trên, nhưng điều đó không hoạt động với các dòng có a "theo sau ,, như trong CSV nơi bạn muốn có một cột duy nhất với chuỗi hello",world, như CSV sẽ đọc:

"hello",world"

Được hiểu là một hàng có hai cột: helloworld"


1
Theo quy tắc chuẩn, bất kỳ trường nào chứa ký tự phân tách hoặc trích dẫn được bao quanh bởi dấu ngoặc kép và bất kỳ dấu ngoặc kép nào bên trong được nhân đôi, do đó không có vấn đề gì. Trường của bạn hello",worldchỉ cần được lưu dưới dạng "hello"",world", có thể được phân tích cú pháp chính xác 100%.
Nyerguds

0
    public static IEnumerable<string> LineSplitter(this string line, char 
         separator, char skip = '"')
    {
        var fieldStart = 0;
        for (var i = 0; i < line.Length; i++)
        {
            if (line[i] == separator)
            {
                yield return line.Substring(fieldStart, i - fieldStart);
                fieldStart = i + 1;
            }
            else if (i == line.Length - 1)
            {
                yield return line.Substring(fieldStart, i - fieldStart + 1);
                fieldStart = i + 1;
            }

            if (line[i] == '"')
                for (i++; i < line.Length && line[i] != skip; i++) { }
        }

        if (line[line.Length - 1] == separator)
        {
            yield return string.Empty;
        }
    }

0

Tôi đã sử dụng thư viện Csvreader nhưng bằng cách sử dụng, tôi đã nhận được dữ liệu bằng cách phát nổ từ dấu phẩy (,) trong giá trị cột.

Vì vậy, nếu bạn muốn chèn dữ liệu tệp CSV chứa dấu phẩy (,) trong hầu hết các giá trị cột, bạn có thể sử dụng hàm bên dưới. Liên kết tác giả => https://gist.github.com/jaywilliams/385876

function csv_to_array($filename='', $delimiter=',')
{
    if(!file_exists($filename) || !is_readable($filename))
        return FALSE;

    $header = NULL;
    $data = array();
    if (($handle = fopen($filename, 'r')) !== FALSE)
    {
        while (($row = fgetcsv($handle, 1000, $delimiter)) !== FALSE)
        {
            if(!$header)
                $header = $row;
            else
                $data[] = array_combine($header, $row);
        }
        fclose($handle);
    }
    return $data;
}

0

Tôi đã sử dụng thư viện papaPude để phân tích tệp CSV và có các cặp giá trị khóa (khóa / tiêu đề / hàng đầu tiên của giá trị tệp CSV).

đây là ví dụ mà tôi sử dụng:

https://codesandbox.io/embed/llqmrp96pm

nó có tập tin dummy.csv trong đó để có bản demo phân tích cú pháp CSV.

Tôi đã sử dụng nó trong ReacJS mặc dù việc sao chép trong ứng dụng được viết bằng bất kỳ ngôn ngữ nào cũng dễ dàng và đơn giản.


0

Một ví dụ có thể giúp hiển thị cách dấu phẩy có thể được hiển thị trong tệp .csv. Tạo một tệp văn bản đơn giản như sau:

Lưu tệp văn bản này dưới dạng tệp văn bản có hậu tố ".csv" và mở tệp đó bằng Excel 2000 từ Windows 10.

aa, bb, cc, d; d "Trong phần trình bày bảng tính, dòng bên dưới sẽ trông giống như dòng trên trừ dòng dưới đây hiển thị dấu phẩy được hiển thị thay vì dấu chấm phẩy giữa d." aa, bb, cc, "d, d", Điều này hoạt động ngay cả trong Excel

aa, bb, cc, "d, d", Điều này hoạt động ngay cả trong Excel 2000 aa, bb, cc, "d, d", Điều này hoạt động ngay cả trong Excel 2000 aa, bb, cc, "d, d", Điều này hoạt động thậm chí trong Excel 2000

aa, bb, cc, "d, d", Điều này không thành công trong Excel 2000 do không gian tin vào trích dẫn thứ nhất aa, bb, cc, "d, d", Điều này thất bại trong Excel 2000 do không gian tin vào trích dẫn thứ nhất aa, bb, cc, "d, d", Điều này không thành công trong Excel 2000 do không gian tin vào trích dẫn thứ nhất

aa, bb, cc, "d, d", Điều này hoạt động ngay cả trong Excel 2000 ngay cả với khoảng trắng trước và sau trích dẫn thứ 2. aa, bb, cc, "d, d", Điều này hoạt động ngay cả trong Excel 2000 ngay cả với khoảng trắng trước và sau trích dẫn thứ 2. aa, bb, cc, "d, d", Điều này hoạt động ngay cả trong Excel 2000 ngay cả với khoảng trắng trước và sau trích dẫn thứ 2.

Quy tắc: Nếu bạn muốn hiển thị dấu phẩy trong ô aa (trường) của tệp .csv: "Bắt đầu và kết thúc trường bằng dấu ngoặc kép, nhưng tránh khoảng trắng trước dấu ngoặc kép thứ nhất"


-1

Tôi nghĩ giải pháp đơn giản nhất cho vấn đề này là yêu cầu khách hàng mở csv trong excel và sau đó ctrl + r để thay thế tất cả dấu phẩy bằng bất kỳ định danh nào bạn muốn. Điều này rất dễ dàng cho khách hàng và chỉ cần một thay đổi trong mã của bạn để đọc dấu phân cách bạn chọn.


Ai nói họ có Excel? Trong thực tế, ai nói rằng ngay cả một con người đang thực hiện việc tải lên? ...
bytedev

-3

Sử dụng ký tự tab (\ t) để phân tách các trường.


4
-1 Tuyệt vời cho đến khi ai đó sử dụng một tab trong giá trị của họ thì bạn quay lại vấn đề mà người đặt câu hỏi đã gặp phải. Trao đổi một char delimiter cho một cái khác sẽ không giải quyết vấn đề.
bytedev

Vô lý. Mọi người không thể nhập các tab trong dữ liệu đầu vào của họ. Trong hầu hết các hình thức, điều đó chỉ đơn giản là di chuyển điểm nhập dữ liệu sang trường tiếp theo.
Pierre

6
"Mọi người không thể nhập các tab trong dữ liệu đầu vào của họ" .... bạn có nghiêm túc không ?? A) tất nhiên một người có thể đặt một tab vào trường nhập B), người nói rằng đó là GUI, dữ liệu đến từ đâu? C) ai nói nó thậm chí là một con người đang nhập dữ liệu?
bytedev
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.