2013-03-01 34 views
19

Tôi đọc từ tệp csv và muốn chia chuỗi dài mà tôi sử dụng stringWithContentsOfFile, là một chuỗi nhiều dòng, với các dòng riêng lẻ đại diện cho các hàng trong tệp csv. Làm thế nào để tôi làm điều này?cách chia chuỗi bằng dòng mới

+0

Tại sao tải toàn bộ tệp vào bộ nhớ? Điều đó sẽ không giúp được dấu chân bộ nhớ của bạn ... – trojanfoe

+0

Có thể nó được biết rằng tập tin sẽ không quá lớn. Nó * là * chỉ cần văn bản ... – uchuugaka

+0

vâng ... tệp đủ nhỏ ... nó chỉ có 54 hàng và 4 cột! –

Trả lời

26

Bạn có thể ngắt chuỗi thành các mảng chuỗi và sau đó thao tác theo ý muốn.

NSArray *brokenByLines=[yourString componentsSeparatedByString:@"\n"] 
+5

Điều này làm cho rất nhiều giả định về những gì tách dòng. – uchuugaka

+1

Nếu bạn không biết các dấu tách dòng là gì: 'let lines = stringData.stringByReplacingOccurrencesOfString (" \ r \ n ", withString:" \ "n"). StringByReplacingOccurrencesOfString ("\ r", withString: "\ n") .componentsSeparatedByString ("\ n") ' – Zaphod

+0

Một không cần phải thay thế @" \ r ", nếu chuỗi được tách ra bằng newLineCharacterSet, –

2

Bạn cần tách nội dung của mình bằng "\ n".

NSString *str= [NSString stringWithContentsOfFile:filePathLib encoding:NSUTF8StringEncoding error:nil]; 
    NSArray *rows = [str componentsSeparatedByString:@"\n"]; 

    for(int i =0;i<[rows count];i++) 
     NSLog(@"Row %d: %@",i,[rows objectAtIndex:i]); 
+1

Điều này cũng làm cho các giả định về các dấu phân cách dòng – uchuugaka

37

Chỉ trong trường hợp bất cứ ai tình cờ gặp câu hỏi này như tôi đã làm. Điều này sẽ hoạt động với bất kỳ ký tự dòng mới nào:

NSCharacterSet *separator = [NSCharacterSet newlineCharacterSet]; 
NSArray *rows = [yourString componentsSeparatedByCharactersInSet:separator]; 
+0

Thậm chí hoạt động với các tệp CSV ... trong đó "\ n" sẽ không. – DogCoffee

+3

Điều này có thể tạo ra các chuỗi rỗng trong mảng nếu các dấu tách dòng là '\ r \ n' (hai ký tự) như xảy ra trong các tệp định dạng của Windows. – Suragch

13

Bạn phải biết rằng \n không phải là ký tự duy nhất được sử dụng để chia một dòng mới. Ví dụ: nếu tệp được lưu trong Windows, các ký tự dòng mới sẽ là \r\n. Đọc the Newline article in Wikipedia để biết thêm thông tin về điều này.

Do đó, nếu bạn chỉ sử dụng componentsSeparatedByString("\n"), bạn có thể nhận được kết quả không mong muốn.

let multiLineString = "Line 1\r\nLine 2\r\nLine 3\r\n" 
let lineArray = multiLineStringRN.componentsSeparatedByString("\n") 
// ["Line 1\r", "Line 2\r", "Line 3\r", ""] 

Lưu ý cả phần còn lại \r và phần tử mảng trống.

Có một số cách để tránh những sự cố này.

Solutions

1. componentsSeparatedByCharactersInSet

let multiLineString = "Line 1\nLine 2\r\nLine 3\n" 
let newlineChars = NSCharacterSet.newlineCharacterSet() 
let lineArray = multiLineString.componentsSeparatedByCharactersInSet(newlineChars).filter{!$0.isEmpty} 
// "[Line 1, Line 2, Line 3]" 

Nếu filter không được sử dụng, sau đó \r\n sẽ tạo ra một phần tử mảng trống rỗng, vì nó được tính là hai nhân vật và do đó tách chuỗi hai lần tại cùng một vị trí.

2. split

let multiLineString = "Line 1\nLine 2\r\nLine 3\n" 
let newlineChars = NSCharacterSet.newlineCharacterSet() 
let lineArray = multiLineString.utf16.split { newlineChars.characterIsMember($0) }.flatMap(String.init) 
// "[Line 1, Line 2, Line 3]" 

hoặc

let multiLineString = "Line 1\nLine 2\r\nLine 3\n" 
let lineArray = multiLineString.characters.split { $0 == "\n" || $0 == "\r\n" }.map(String.init) 
// "[Line 1, Line 2, Line 3]" 

Đây \r\n được tính là một nhân vật Swift duy nhất (một cụm grapheme mở rộng)

3. enumerateLines

let multiLineString = "Line 1\nLine 2\r\nLine 3\n" 
var lineArray = [String]() 
multiLineString.enumerateLines { (line, stop) ->() in 
    lineArray.append(line) 
} 
// "[Line 1, Line 2, Line 3]" 

Để biết thêm về cú pháp enumerateLine, hãy xem this answer.

Ghi chú:

  • một dòng chuỗi đa sẽ không thường đan xen cả \r\n\n nhưng tôi đang làm điều này ở đây để chứng minh rằng các phương pháp này có thể xử lý cả hai định dạng.
  • NSCharacterSet.newlineCharacterSet() là các ký tự dòng mới được định nghĩa là (U + 000A – U + 000D, U + 0085), bao gồm \r\n.
  • Câu trả lời này là bản tóm tắt các câu trả lời cho my previous question. Đọc những câu trả lời đó để biết thêm chi tiết.
4

Swift 3 phiên bản:

let lines = yourString.components(separatedBy: .newlines) 

Nice và ngắn.

0

Dưới đây là quan điểm của tôi về nó:

NSString* string = @"FOO\r\nBAR\r\r\n\rATZ\rELM327 v1.5"; 
    NSCharacterSet* newlineSet = [NSCharacterSet newlineCharacterSet]; 
    NSCharacterSet* whitespaceSet = [NSCharacterSet whitespaceAndNewlineCharacterSet]; 
    NSArray<NSString*>* components = [string componentsSeparatedByCharactersInSet:newlineSet]; 
    NSPredicate* predicate = [NSPredicate predicateWithBlock:^BOOL(NSString* _Nullable string, NSDictionary<NSString *,id> * _Nullable bindings){ 
     return [string stringByTrimmingCharactersInSet:whitespaceSet].length > 0; 
    }]; 
    NSArray<NSString*>* lines = [components filteredArrayUsingPredicate:predicate]; 

    [lines enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 
     NSLog(@"Line %u = '%@'", idx, obj); 
    }]; 

Chạy in này:

2017-10-24 15:26:05.380 Untitled 5[64977:3182818] Line 0 = 'FOO' 
2017-10-24 15:26:05.380 Untitled 5[64977:3182818] Line 1 = 'BAR' 
2017-10-24 15:26:05.380 Untitled 5[64977:3182818] Line 2 = 'ATZ' 
2017-10-24 15:26:05.380 Untitled 5[64977:3182818] Line 3 = 'ELM327 v1.5' 

Nó có thể không phải là cách hiệu quả nhất (có thể sử dụng một NSScanner sẽ nhanh hơn), nhưng nó quyết định vấn đề ở đây.

Các vấn đề liên quan