Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

vukid

macrumors newbie
Original poster
Oct 10, 2013
9
0
I need to read in a csv file into a string and break all the comma separated words

i.e. : house, city, street, zip

and then put them into arrays so I can output the the rows in the cvs individually, but i'm an new to coding so I do not know where to start, any help would be great.
 
Last edited:

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
I need to read in a cvs file into arrays so I can output the the rows in the cvs individually, but i'm an new to coding so I do not know where to start, any help would be great.

What you say doesn't make any sense.

Are you sure you want to read cvs files? Canvas 3 drawing file? I would find it highly impolite if you couldn't even be bothered to check the spelling of what you are asking for.
 

Niklas Korz

macrumors newbie
Oct 7, 2013
3
0
Germany
Well, basically it's pretty easy. For my example, I'll assume that you've already read the CSV file and put it's content into a string called "content".

Code:
NSMutableArray *entries = [[NSMutableArray alloc] init];
for (NSString *line in [content componentsSeparatedByString:@"\n"]) {
    NSArray *rows = [line componentsSeparatedByString:@";"]; // ';' can be any separator, e.g. \t or just a comma
    [entries addObject:rows];
}

There's probably a more efficient way, but you get the idea.
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
Well, basically it's pretty easy. For my example, I'll assume that you've already read the CSV file and put it's content into a string called "content".

Code:
NSMutableArray *entries = [[NSMutableArray alloc] init];
for (NSString *line in [content componentsSeparatedByString:@"\n"]) {
    NSArray *rows = [line componentsSeparatedByString:@";"]; // ';' can be any separator, e.g. \t or just a comma
    [entries addObject:rows];
}

There's probably a more efficient way, but you get the idea.

A method that actually works would be preferable. For example, if you get a line like

1997,Ford,E350,"Super, luxurious truck"

(from the Wikipedia article)

Just search for "CSV file format", figure out what encoding and what separator, and then read the file into an NSString and examine the characters byte by byte, check for quotes, double quotes, separators, carriage returns, line feeds. I mean what are the bets that the file comes from a Windows machine, code page 1252, CR/LF pairs?
 
Last edited:

vukid

macrumors newbie
Original poster
Oct 10, 2013
9
0
I still am not sure how to read a .cvs file to a String yet, some help on that will help also. How would output that for NSLog?
 

devilofspades

macrumors member
Jul 20, 2011
76
0
Code:
NSString *sourceFileString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"filename" ofType:@"csv"] encoding:NSUTF8StringEncoding error:nil];


NSMutableArray *csvArray = [[NSMutableArray alloc] init];
    
csvArray = [[sourceFileString componentsSeparatedByString:@"\n"] mutableCopy];

NSString *keysString = [csvArray objectAtIndex:0];
    
NSArray *keysArray = [keysString componentsSeparatedByString:@","];
    
[csvArray removeObjectAtIndex:0];

from here it all depends on where you want to go. i use this same process to create dictionaries of and nest those in another dictionary. but each use case is going to be different. this is a good jumping off point for you to work out the rest.
 
Last edited by a moderator:

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
Code:
NSString *sourceFileString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"filename" ofType:@"csv"] encoding:NSUTF8StringEncoding error:nil];


NSMutableArray *csvArray = [[NSMutableArray alloc] init];
    
csvArray = [[sourceFileString componentsSeparatedByString:@"\n"] mutableCopy];

NSString *keysString = [csvArray objectAtIndex:0];
    
NSArray *keysArray = [keysString componentsSeparatedByString:@","];
    
[csvArray removeObjectAtIndex:0];

from here it all depends on where you want to go. i use this same process to create dictionaries of and nest those in another dictionary. but each use case is going to be different. this is a good jumping off point for you to work out the rest.

I think you are making a wrong assumption here. The OP wants to read .cvs files, which are a totally different thing. He said it twice. After being asked to check.
 
Last edited by a moderator:

vukid

macrumors newbie
Original poster
Oct 10, 2013
9
0
yes, i need to read the .cvs file to a string then create arrays to where i can output a whole row with the home, city,........ that matches what a user input wants to see.
 

devilofspades

macrumors member
Jul 20, 2011
76
0
I think you are making a wrong assumption here. The OP wants to read .cvs files, which are a totally different thing. He said it twice. After being asked to check.

this is exactly what this code does. if you took the time to look at it you would see that. as i said, each case is going to be different and vary depending how the csv is formatted. the "op" also needs to understand what is going on and can't expect to cut and paste code and expect to have a successful app. once they figure this out, they will realize that an array is not what they want. its a good start, but in the end a csv is 2 dimensional array, and hence is better suited for a dictionary or nested dictionaries.
 

vukid

macrumors newbie
Original poster
Oct 10, 2013
9
0
I'm pretty new to objective c, sorry, I would I go about outputting a name match from the array above to a user input?

----------

Also, what folder on the computer would i put the .cvs file so that xcode can read the file?
 

chown33

Moderator
Staff member
Aug 9, 2009
10,747
8,421
A sea of green
I'm pretty new to objective c, sorry, I would I go about outputting a name match from the array above to a user input?

Instead of having other people write your program for you in a series of questions, please tell us what you do know about Objective-C. Also describe what you know about programming in general, such as any other programming languages you already know.

If you studied an online tutorial, what is its URL, and exactly where are you in studying it?

If you're working from a book, exactly which book? Title, author, edition.

If you haven't done anything, and are expecting to have a working program after just some copy-and-paste from randomly collected pieces of code, then your expectation is mistaken.
 

devilofspades

macrumors member
Jul 20, 2011
76
0
I'm pretty new to objective c, sorry, I would I go about outputting a name match from the array above to a user input?

ok, so the code i posted breaks down line this. first it takes the entire csv file and makes a string out of it. it then takes that string and then creates and array of each line or "row" separated by a line break. from there it creates another array (keysArray) using the first "line" of the csv file stored in the previous array, these are your "column headers". what's left is an array of each "row" of the csv file. this is where it gets tricky and depends on how you plan to use it. each object in the array is a row from the csv, but that info is useless without some context to the column title / name / header, etc. this is why i said it would depend on the use case. my suggestions / recommendation (also the direction my code is headed) is to create separate dictionaries for each row of the csv. the keys of that dictionary would be the column titles. from there you would essentially have a 2 row csv. then if you did that for every row you could then encapsulate each of those dictionaries in array, or better yet another dictionary with a unique key name for each row you stored as a dictionary, such as a persons name or address etc. this way you could extract the whole "row" of information by a key value and that "row" would already be organized by keys of the "column names".

this all starting to make sense?
 

vukid

macrumors newbie
Original poster
Oct 10, 2013
9
0
I understand the logic, just not the coding itself since i am coming from c++. Can you show me from the code above what i have to do next to get the name of the user input from the array?
 

devilofspades

macrumors member
Jul 20, 2011
76
0
I understand the logic, just not the coding itself since i am coming from c++. Can you show me from the code above what i have to do next to get the name of the user input from the array?

if you could give me a simplified version of the csv you will be using i can break it down. i just need you to put something with just 3 or 4 lines. also, let me know how you want to reference or pull that data once its stored. the thing to keep in mind is that an array stores data by index numbers. nothing can be retrieved via a string name, hence my suggestion to use dictionaries.

for everyone else reading this, disregard tableviews and "row at index" for now as i don't want to over complicate this.
 

vukid

macrumors newbie
Original poster
Oct 10, 2013
9
0
I need to prompt user to enter a city name and then output the city prompt by user and display it on console,
my cvs file looks like this:

City,Country,Latitude,Longitude
Aberdeen, Scotland,57.15,-2.15
Adelaide, Australia,-34.91666667,138.6
Algiers, Algeria,36.83333333,3
Amsterdam, Netherlands,52.36666667,4.883333333
Ankara, Turkey,39.91666667,32.91666667
....


Code:
#import <Foundation/Foundation.h>
#import <string.h>
int main(int argc, const char * argv[])

{
    @autoreleasepool {
        
        //input user for a name on city list       
         char input[100];

        do 
        {
            
            NSLog(@"The worldcities.cvs contained infor on 120 cities.");         
            NSLog(@"Enter a city by name: ");   
            fgets( input, 100, stdin );
            NSString *sourceFileString = [NSString stringWithContentsOfFile:      [[NSBundle mainBundle] pathForResource:@"worldcities" ofType:@"csv"] encoding:NSUTF8StringEncoding error:nil];
            
            NSMutableArray *csvArray = [[NSMutableArray alloc] init];
            
            csvArray = [[sourceFileString componentsSeparatedByString:@"\n"] mutableCopy];
            
            NSString *keysString = [csvArray objectAtIndex:0];
            
            NSArray *keysArray = [keysString componentsSeparatedByString:@","];
            
            [csvArray removeObjectAtIndex:0];
}while(true)
}
return 0;

your code above also has a unused variable 'keysArray' pop up when ran.
 
Last edited:

devilofspades

macrumors member
Jul 20, 2011
76
0
if your starting csv looks like this...

City,Country,Latitude,Longitude
Aberdeen, Scotland,57.15,-2.15
Adelaide, Australia,-34.91666667,138.6
Algiers, Algeria,36.83333333,3
Amsterdam, Netherlands,52.36666667,4.883333333
Ankara, Turkey,39.91666667,32.91666667


then here is the process..

Code:
// sets a string to be the value of the file
    NSString *sourceFileString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"your filename" ofType:@"csv"] encoding:NSUTF8StringEncoding error:nil];

your string will be a multiline representation of your csv file. 

// create an editable array
    NSMutableArray *csvArray = [[NSMutableArray alloc] init];
    
    
// set the contents of the array to the contents of the string separated by line break
    csvArray = [[sourceFile componentsSeparatedByString:@"\n"] mutableCopy];
    
    
// create a string with the value of the title / name of the "columns" by pulling the first entry of the array
    NSString *keysString = [csvArray objectAtIndex:0];
       
your result will be @"City,Country,Latitude,Longitude"

    
// create an array to store the column names seperated by commas
    NSArray *keysArray = [keysString componentsSeparatedByString:@","];
    
*your result will be (
			City, <--index:0 
			Country, <--index:1
			Latitude, <--index:2
			Longitude <--index:3
			)

    
    
// remove the first object in the array that is storing the column names, leaving only data left
    [csvArray removeObjectAtIndex:0];
   
**your csvArray will now be (
				Aberdeen, Scotland,57.15,-2.15  <--index:0
				Adelaide, Australia,-34.91666667,138.6 <--etc…
				Algiers, Algeria,36.83333333,3
				Amsterdam, Netherlands,52.36666667,4.883333333
				Ankara, Turkey,39.91666667,32.91666667
				)


    
// create an editable dictionary to store final data
    NSMutableDictionary *outputDict = [[NSMutableDictionary alloc]init];
    
    
// create a while loop to keep track of the amount of items in the csvArray
// a "nil" value is always the last item in an array or dictionary hence the value of 1 and not 0
// 1 would essentially be an "empty" array or dictionary
    while (csvArray.count > 1)
    {
        
        // create a string to store each line of info from the first item in the array
        NSString *tempString = [csvArray objectAtIndex:0];

your first result would be @"Aberdeen, Scotland,57.15,-2.15"
this will change for every sequence of the loop
        
        
        
// create an array to store those items seperated by a comma
        NSArray *tempArray = [tempString componentsSeparatedByString:@","];

your first result would be (
				Aberdeen, 
				Scotland,
				57.15,
				-2.15  
				)     
        
        
// creates a temp dictionary to store the contents of the tempArray with key values of the column names stored in keysArray
        NSDictionary *tempDictionary = [[NSDictionary alloc]initWithObjects:tempArray forKeys:keysArray];
        

your result would be {
			Aberdeen = City;
			Scotland = Country;
			57.15 = Latitude;
			-2.15 = Longitude; 
			}    
        
        
// adds the tempDictionary to the master dictionary with a key value of the city name that was parsed
// from the tempArray (see *)
        [outputDict setObject:tempDictionary forKey:[tempArray objectAtIndex:0]];
        
        
        
// removes the first item in the array (the first "row" of the csv) which bumps the next line in the array up to index 0 (see **)
        [csvArray removeObjectAtIndex:0];
        
        
        // will repeat and remove one row at a time until the "master dictionary" is filled with a each "city" dictionary
    }

to access the data by city you would just call
Code:
  [outputDict objectForKey:@"the city name you want"];

if you want say the longitude for Aberdeen, you would use
Code:
 [outputDict valueForKeyPath:@"Aberdeen.Longitude"];


that's about as detailed as i can and willing to get. just don't cut and paste this, learn how and what is being done. the reason you got an "unused variable" is because that wasn't the complete set of code. also, i typed all this out in texteditor so i would manually type it all out in xcode because im sure there are a ton of typos.
 
Last edited:

vukid

macrumors newbie
Original poster
Oct 10, 2013
9
0
thank you, I will try and see if this will work with what I want to use the data for.
 

devilofspades

macrumors member
Jul 20, 2011
76
0
thank you, I will try and see if this will work with what I want to use the data for.

you can see from the code that the csv is parsed into multiple arrays as per your original request but you can some what infer by the output and comments that this data is somewhat useless simply because of the lack of "organization". you could store all those arrays into other arrays but retrieving granular data becomes difficult unless you implement a tableview that can display all the info.
 

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
this is exactly what this code does. if you took the time to look at it you would see that. as i said, each case is going to be different and vary depending how the csv is formatted. the "op" also needs to understand what is going on and can't expect to cut and paste code and expect to have a successful app. once they figure this out, they will realize that an array is not what they want. its a good start, but in the end a csv is 2 dimensional array, and hence is better suited for a dictionary or nested dictionaries.

You wrote code to read .csv files. That's not what the OP asked for. He asked for code to read .cvs files.

http://www.fileinfo.com/extension/cvs

What he _wants_, I don't know. But .cvs is what he asked for, not .csv.
 

devilofspades

macrumors member
Jul 20, 2011
76
0
You wrote code to read .csv files. That's not what the OP asked for. He asked for code to read .cvs files.

http://www.fileinfo.com/extension/cvs

What he _wants_, I don't know. But .cvs is what he asked for, not .csv.

im sure the op can confirm that "cvs" is a typo. given what it is they want to do and using some, ummm what's the term...common sense, and seeing that other posters pointed out the same info. we can pretty much figure when the op put

I need to read in a cvs file into a string and break all the comma separated words...

it's a safe bet they meant csv or "comma separated values"

http://www.fileinfo.com/extension/csv
 
Last edited:

gnasher729

Suspended
Nov 25, 2005
17,980
5,565
im sure the op can confirm that "cvs" is a typo.

See my first post. He surely never confirmed that. Maybe he wants to read comma veparated salues. :D

Anyway: In a file with comma separated values, if an item starts with a quote character ", then it extends up to the next single quote character, even if there are commas and carriage return or linefeed characters in between. The first and last quote should be removed, and double quotes inside replaced with single quotes.
 
Last edited:

devilofspades

macrumors member
Jul 20, 2011
76
0
See my first post. He surely never confirmed that. Maybe he wants to read comma veparated salues. :D

Anyway: In a file with comma separated values, if an item starts with a quote character ", then it extends up to the next single quote character, even if there are commas and carriage return or linefeed characters in between. The first and last quote should be removed, and double quotes inside replaced with single quotes.

ideally one needs to check the formatting of their source file, but the process i gave doesn't care wether there are quotes or not. if there are, then you will just end up with double or single quotes in your string names. if you have double quotes in your csv then it will still separate it at the comma. most csv files won't have double quotes anyways since spaces are acceptable in a csv.
 

chown33

Moderator
Staff member
Aug 9, 2009
10,747
8,421
A sea of green
ideally one needs to check the formatting of their source file, but the process i gave doesn't care wether there are quotes or not. if there are, then you will just end up with double or single quotes in your string names. if you have double quotes in your csv then it will still separate it at the comma. most csv files won't have double quotes anyways since spaces are acceptable in a csv.

Quoting is also used to embed a comma (or other special character) in a field value. Without quotes, an embedded comma would be a delimiter. With quotes, the comma is NOT a delimiter. Your code doesn't handle this case.
http://en.wikipedia.org/wiki/Comma-separated_values#Toward_standardization

It's unclear whether the code even needs to handle quoted commas. If the data were really house, city, state, zip as posted in the 1st post, then it's conceivable a comma could appear in the "house" field. But since the data isn't that, it's unclear what the real constraints for the data are.
 

vukid

macrumors newbie
Original poster
Oct 10, 2013
9
0
Check the posts below I commented, I need to read a comma separated file into arrays n output the correct array to console based on user string input match?
 

robvas

macrumors 68040
Mar 29, 2009
3,240
629
USA
You sure you don't want to load them into CoreData and that way you can query etc?
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.