1

I want to get all filenames and directories from a provided web url so I can easily create links to those files/directories in my app.

I am having trouble figuring out the best way to parse the text file returned when using NSURLSession's 'dataTaskWithRequest' method since it returns all the data for the contents at the url (i.e. permissions, date created, owner, group, etc.).

Here is how I get the data from a Web URL:

    let request = NSURLRequest(URL: url)
    let session = NSURLSession.sharedSession()
    let task = session.dataTaskWithRequest(request) {[weak self] (data, response, error) -> Void in
        print("Data: \(data)")
        print("Response: \(response)")
        print("Error: \(error)")

        if let weakSelf = self, let data = data, let results = NSString(data: data, encoding: NSASCIIStringEncoding)
        {
            ...how do I parse out the file/directory names???...
        }
    }
    task.resume()

Here is an example of string returned from a given URL:

drwxrwxr-x   26 65534    65534       65536 Sep 20 03:29 Movies
drwxrwsr-x    3 0        65534       65536 Jul 09  2013 Network Trash Folder
drwxrwxr-x   41 65534    65534       65536 Aug 24 15:58 TV
drwxrwsr-x    3 0        65534       65536 Jul 09  2013 Temporary Items

I need to be able to easily and accurately parse out the file/directory names ONLY so I can create links to them. Suggestions?

JimmyJammed
  • 9,598
  • 19
  • 79
  • 146
  • So this string returned is nothing but 'Response:' ? And you need only strings parsed, means only 'Movies', 'Network Trash Folder', etc. ? Please correct me if I am interpreting it wrong. Thanks. – Tushar J. Sep 23 '15 at 04:06
  • @TusharJ. No, all that data (i.e. files/directories, permissions, etc) is currently returned as one long string. I need to parse it so I can get just a list of the directories and files as an array of strings. (i.e. ["Movies", Network Trash Folder", "TV", "Temporary Items"]). – JimmyJammed Sep 30 '15 at 02:09

1 Answers1

0

Assuming your strings are separated by new line character, you can address this by following:

Step 1: Add a method to return word in the entire string

- (NSString *)lastComponentFromString:(NSString *)iString {
    NSRange range= [iString rangeOfString: @" " options: NSBackwardsSearch];
    return  [iString substringFromIndex: range.location+1];   
}

Step 2: Add a method to return entire string but last word

- (NSString *)stringAfterRemovingLastComponentFromString:(NSString *)iString {
    NSRange range= [iString rangeOfString: @" " options: NSBackwardsSearch];
    return [iString substringToIndex: range.location];
}

Step 3: Add a method to trim leading and trailing spaces

- (NSString *)trimString:(NSString *)iBaseString {
    return (iBaseString && ![iBaseString isKindOfClass:[NSNull class]] && iBaseString.length > 0) ? [iBaseString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]] : nil;
}

Step 4: Add a method for number validation check:

- (BOOL)numberValidation:(NSString *)text {
    NSString *regex = @"^([0-9]*|[0-9]*[.:][0-9]*)$";
    NSPredicate *test = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex];
    BOOL isValid = [test evaluateWithObject:text];
    return isValid;
}

Step 5: Add a method to take one line at a time, call above methods and return the final folder name. Here we will keep on finding folder until we hit a number.

- (NSString *)folderNameForPathString:(NSString *)iPathString {
    NSString *lastComponent = [self lastComponentFromString:iPathString];
    NSString *remainingString = [self stringAfterRemovingLastComponentFromString:iPathString];
    NSString *finalFolder = @"";

    while (lastComponent.integerValue == 0) {
        NSString *initialSpaceString = [NSString stringWithFormat:@" %@", finalFolder];

    // Check if the next component is a number
    if ([self numberValidation:lastComponent]) {
        lastComponent = @"";
    }
        finalFolder = [lastComponent stringByAppendingString:initialSpaceString];
        lastComponent = [self lastComponentFromString:remainingString];
        remainingString = [self stringAfterRemovingLastComponentFromString:remainingString];
    }

    return [self trimString:finalFolder];
}

Step 6: Finally, parse your server string to get individual strings separate by new line character.

NSString *data =  @"drwxrwxr-x   26 65534    65534       65536 Sep 20 03:29 Movies\ndrwxrwsr-x    3 0        65534       65536 Jul 09  2013 Network Trash Folder\ndrwxrwxr-x   41 65534    65534       65536 Aug 24 15:58 TV\ndrwxrwsr-x    3 0        65534       65536 Jul 09  2013 Temporary Items";

NSArray *lineArray = [data componentsSeparatedByString:@"\n"];
NSMutableArray *folders = [NSMutableArray array];

for (NSString *pathString in lineArray) {
    [folders addObject:[self folderNameForPathString:pathString]];
}

NSLog(@"folders = %@", folders); // This prints - Movies, Network Trash Folder, TV, Temporary Items
Abhinav
  • 37,684
  • 43
  • 191
  • 309
  • Thanks! This looks great, and I tried implementing it, but am getting hung up on this part as it never is true. Any suggestions?: while (lastComponent.integerValue == 0) { ... } – JimmyJammed Sep 30 '15 at 01:41
  • It had worked for me like a charm and reason it can fail is if your string just before folder name does not contain a number. I had written that considering your sample. Which string fails this? I am right now away from my system and would take few hours reaching it so will take a look once I am back. – Abhinav Sep 30 '15 at 01:48
  • Url String: ftp://NitWitsMedia.local./ Data: Optional(<64727778 72777372 2d782020 20313120 36353533 34202020 20363535 33342020 20202020 20363535 33362053 65702033 30203030 3a333620 5075626c 69630d0a>) Response: Optional( { URL: ftp://nitwitsmedia.local./ }) Error: nil Lines: ["drwxrwsr-x 11 65534 65534 65536 Sep 30 00:36 Public\r", ""] lastComponentFromString: "Public " startIndex: 55 endIndex: 56 stringAfterRemovingLastComponentFromString: Public Integer value: nil folderNameForPathString: nil – JimmyJammed Sep 30 '15 at 01:51
  • Instead of NSData can you please paste string here that fails. Paste the entire string. You may edit your question also. – Abhinav Sep 30 '15 at 02:00
  • String to Parse: drwxrwsr-x 11 65534 65534 65536 Sep 30 00:36 Public – JimmyJammed Sep 30 '15 at 02:06
  • The issue that I see with your this string that the portion just before the folder name was "00:36" which was failing number check in the code I shared. I have fixed that and tried with the string you shared and its working all good for me. If you are expecting more special characters to come in your string then you can modify regex in `numberValidation:` method and it should work all fine. – Abhinav Sep 30 '15 at 03:29
  • I would advise you to run this code with just one string that you shared with me once and then try with your entire data. – Abhinav Sep 30 '15 at 03:30
  • Yes, I realized this shortly after posting this question. I had to update the code to check for both dates and times to know if i reached the end of the filename. Thanks for your help! – JimmyJammed Oct 03 '15 at 20:57