Read lines from big text file in Swift until new line is empty: the Swift way
Asked Answered
G

1

7

I have the following text file structure (the text file is pretty big, around 100,000 lines):

A|a1|111|111|111
B|111|111|111|111

A|a2|222|222|222
B|222|222|222|222
B|222|222|222|222

A|a3|333|333|333
B|333|333|333|333

...

I need to extract a piece of text related to a given key. For example, if my key is A|a2, I need to save the following as a string:

A|a2|222|222|222
B|222|222|222|222
B|222|222|222|222

For my C++ and Objective C projects, I used the C++ getline function as follows:

std::ifstream ifs(dataPathStr.c_str());

NSString* searchKey = @"A|a2";
std::string search_string ([searchKey cStringUsingEncoding:NSUTF8StringEncoding]);

// read and discard lines from the stream till we get to a line starting with the search_string
std::string line;

while( getline( ifs, line ) && line.find(search_string) != 0 );

// check if we have found such a line, if not report an error
if( line.find(search_string) != 0 )
{
 data = DATA_DEFAULT ;
}

else{

   // we need to form a string that would include the whole set of data based on the selection
   dataStr = line + '\n' ; // result initially contains the first line

   // now keep reading line by line till we get an empty line or eof
   while(getline( ifs, line ) && !line.empty() )
   {
      dataStr += line + '\n'; // append this line to the result
   }

   data = [NSString stringWithUTF8String:navDataStr.c_str()];
} 

As I am doing a project in Swift, I am trying to get rid of getline and replace it with something "Cocoaish". But I cannot find a good Swift solution to address the above problem. If you have an idea, I would really appreciate it. Thanks!

Gonadotropin answered 10/11, 2014 at 3:45 Comment(6)
possible duplicate of Read a file/URL line-by-line in SwiftLeflore
Interesting link, thank you. But it is not working as given: returns the full database and does not stop at /n or /n/r. Best.Gonadotropin
I have tested it once more: Each nextLine() call returns one line from the file as a String. The default delimiter is the newline character (\n). The delimiter is not included in the returned string.Leflore
Thanks a lot, Martin. I will check it again later today. Best.Gonadotropin
Sorry. Added your StreamReader.swift file and implemented the following in UIViewController: let bundle = NSBundle.mainBundle() let pathNav = bundle.pathForResource("data_apt", ofType: "txt") if let aStreamReader = StreamReader(path: pathNav!) { while let line = aStreamReader.nextLine() { println(line) } Still reading the full database as opposed to lines to delimiter \n.Gonadotropin
I have tested it and it worked for me. Code added as an answer.Leflore
L
10

Using the StreamReader class from Read a file/URL line-by-line in Swift, you could do that it Swift like this:

let searchKey = "A|a2"

let bundle = NSBundle.mainBundle()
let pathNav = bundle.pathForResource("data_apt", ofType: "txt")
if let aStreamReader = StreamReader(path: pathNav!) {
    var dataStr = ""
    while let line = aStreamReader.nextLine() {
        if line.rangeOfString(searchKey, options: nil, range: nil, locale: nil) != nil {
            dataStr = line + "\n"
            break
        }
    }
    if dataStr == "" {
        dataStr = "DATA_DEFAULT"
    } else {
        while let line = aStreamReader.nextLine() {
            if countElements(line) == 0 {
                break
            }
            dataStr += line + "\n"
        }
    }
    aStreamReader.close()
    println(dataStr)
} else {
    println("cannot open file")
}
Leflore answered 11/11, 2014 at 8:56 Comment(1)
Martin. This is brilliant. Thank you so much! I have actually found the problem. The dataset text file was created in Windows and there was an issue with line breaks. I have recreated it in Mac using TextWrangler with Line breaks Unix(LF) and viola! Any conditions to use your code in a commercial project (of course, in addition to putting your name as a Copyright in the code)? Thank you so much!Gonadotropin

© 2022 - 2024 — McMap. All rights reserved.