2013-03-01 9 views
19

Czytam z pliku csv i chcę podzielić długi ciąg, który otrzymuję za pomocą stringWithContentsOfFile, który jest ciągiem o wielu wierszach, z pojedynczymi wierszami reprezentującymi wiersze w pliku csv. Jak mam to zrobic?jak podzielić ciąg znaków z znakami nowej linii

+0

Po co ładować cały plik do pamięci? To nie pomoże twojemu śladowi pamięci ... – trojanfoe

+0

Może wiadomo, że plik nie będzie tak duży. It * is * just text ... – uchuugaka

+0

tak ... plik jest wystarczająco mały ... ma tylko 54 wiersze i 4 kolumny! –

Odpowiedz

26

Możesz przerwać ciąg na tablice ciągów, a następnie manipulować nimi, jak chcesz.

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

To daje wiele założeń co do tego, jakie są separatory linii. – uchuugaka

+1

Jeśli nie wiesz, co to są separatory linii: 'let lines = stringData.stringByReplacingOccurrencesOfString (" \ r \ n ", withString:" \ "n"). StringByReplacingOccurrencesOfString ("\ r", withString: "\ n") .componentsSeparatedByString ("\ n") ' – Zaphod

+0

Nie trzeba zastępować @" \ r ", jeśli ciąg jest oddzielony newLineCharacterSet; –

2

Musisz oddzielić zawartość za pomocą "\ 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

To również tworzy założenia dotyczące separatorów linii – uchuugaka

37

Na wypadek, gdyby ktoś natknął się na to pytanie tak jak ja. To będzie pracować z dowolnymi znakami nowej linii:

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

Działa nawet z plikami CSV ... gdzie "\ n" nie będzie. – DogCoffee

+3

Może wytworzyć puste ciągi w tablicy, jeśli separatory linii są '\ r \ n' (dwa znaki) tak, jak dzieje się to w plikach w formacie Windows. – Suragch

13

Trzeba mieć świadomość, że \n nie jedyny znak używany do dzielenia nową linię. Na przykład, jeśli plik został zapisany w systemie Windows, znaki nowej linii będą następujące: \r\n. Przeczytaj the Newline article in Wikipedia, aby uzyskać więcej informacji na ten temat.

Tak więc, jeśli po prostu użyjesz componentsSeparatedByString("\n"), możesz uzyskać nieoczekiwane wyniki.

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", ""] 

Należy zwrócić uwagę na resztę \r i pusty element tablicy.

Istnieje kilka sposobów na uniknięcie tych problemów.

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]" 

Jeśli filter nie były używane, a następnie \r\n przyniosłoby pusty element tablicy, ponieważ jest ona liczona jako dwa znaki i tak oddziela ciąg dwukrotnie u ta sama lokalizacja.

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]" 

lub

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]" 

Tutaj \r\n dostaje liczone jako jeden znak Swift (rozszerzony grafem cluster)

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]" 

Aby uzyskać więcej informacji o składni enumerateLine, zobacz także: this answer.

Uwagi:

  • multi linia ciąg nie będzie zwykle mieszać zarówno \r\n i \n ale robię to, żeby pokazać, że metody te mogą obsługiwać oba formaty.
  • NSCharacterSet.newlineCharacterSet() są znakami nowej linii zdefiniowanymi jako (U + 000A-U + 000D, U + 0085), które obejmują \r i \n. Ta odpowiedź jest podsumowaniem odpowiedzi na my previous question. Przeczytaj te odpowiedzi, aby uzyskać więcej szczegółów.
4

Swift 3 wersja:

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

Nicea i krótkie.

0

Oto moje zdanie na jej temat:

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); 
    }]; 

Uruchomienie tego drukuje:

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' 

To może nie być najbardziej efektywny sposób (prawdopodobnie za pomocą NSScanner byłoby szybciej), ale to rozwiązuje problem tutaj.

Powiązane problemy