Truncate string values from txt file and add to array - iphone

I have a txt file which was copied to Supporting Files of my Xcode project.The data in txt file is of format:
abacus#frame with balls for calculating
abate#to lessen to subside
abdication#giving up control authority
aberration#straying away from what is normal
....................around 4000 lines
I have successfully extracted data from the file using the below code:
NSString *greFileString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"grewords" ofType:#"txt"] encoding:NSUTF8StringEncoding error:nil];
self.greWordsArray = [NSMutableArray arrayWithArray:[greFileString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
When I print greWordsArray,I could see the below output in log
"abacus#frame",
with,
balls,
for,
calculating,
"",
"abate#to",
lessen,
to,
subside,
"",
"abdication#giving",
up,
control,
authority,
"",
"aberration#straying",
away,
from,
what,
is,
normal,
"",
But I want the values in two separate arrays,one holding abacus,abate,abdication,authority aberration and other array with frame with balls for calculating,to lessen to subside,giving up control,straying away from what is normal i.e. one array holding string before # symbol and one with after # symbol
I know there are several methods like checking for special character method,string by replacing occurrences of string,using character set,but the fact is since my string greFileString is a bundle holding multiple strings,if I try any of these methods only abacus is getting added to array,but I want abacus,abate,abdication,aberration to be added to array.
EDIT
Following suggestion of H2CO3,I have implemented the following way:
NSString *greFileString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"grewords" ofType:#"txt"] encoding:NSUTF8StringEncoding error:nil];
NSArray *greData = [NSArray arrayWithArray:[greFileString componentsSeparatedByString:#"#"]];
self.greWordsArray = [NSMutableArray array];
self.greWordHints = [NSMutableArray array];
for (NSString *greWord in greData)
{
if ([greWord characterAtIndex:0] == (unichar)'#')
{
[greWordHints addObject:greWord];
}
else
{
[greWordsArray addObject:greWord];
}
}
NSLog(#"gre words are %#",greWordsArray);
NSLog(#"gre hints are %#",greWordHints);
Here is the logged output:
gre words are (
abacus,
"frame with balls for calculating
\nabate",
"to lessen to subside
\nabdication",
"giving up control authority
\naberration",
"straying away from what is normal
\nabet",
"help/encourage somebody (in doing wrong)
\nabeyance",
"suspended action
\nabhor",
"to hate to detest
gre hints are (
)
Can someone please guide me on this?

It's quite trivial: if the first character of the string is a '#', then put it in the one array, else put it in the other one.
NSArray *words = [greFileString componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSMutableArray *at = [NSMutableArray array];
NSMutableArray *noAt = [NSMutableArray array];
for (NSString *s in words)
if ([s characterAtIndex:0] == (unichar)'#')
[at addObject:s];
else
[noAt addObject:s];
Disregard the above - OP was lying to me >.< The text file actually consists of lines in which an at-symbol delimits the word and the explanation, i. e.
word1#explanation one
word2#explanation two
etc. This means that first the lines should be retrieved (perhaps using - [NSString componentsSeparatedByString:]), then each line is to be split into two part (the same method is useful here too).

Finally got it working,initially my idea was right,but couldn't execute it properly.First of all we need to fetch the data from txt file and place in array.Then as H2CO3 mentioned we need to loop through and here we need to implement components Separated By String.Now we are ready with data,what needs to be done is placing data in arrays using array object at index 0 in words and 1 in hints,i.e.:
NSString *greFileString = [NSString stringWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"grewords" ofType:#"txt"] encoding:NSUTF8StringEncoding error:nil];
self.greWordHints = [NSMutableArray array];
self.greWordsArray = [NSMutableArray array];
NSArray *greWords = [NSMutableArray arrayWithArray:[greFileString componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]]];
for (NSString *greWord in greWords)
{
if (greWord && greWord.length)
{
NSArray *trimmedGreData = [greWord componentsSeparatedByString:#"#"];
[greWordsArray addObject:[trimmedGreData objectAtIndex:0]];
[greWordHints addObject:[trimmedGreData objectAtIndex:1]];
}
}
Hope it helps some one,thanks :)

Related

Compare arrays ios

How to compare 2 arrays with different value
Array one has words en the other has images
NSDictionary *dict = [NSDictionary dictionaryWithObjects:array2 forKeys:array1];
I think you need to use an NSDictionary. This is how you do that (using the new Objective C literal syntax)
NSDictionary *dictionary = #{
#"dog" : #"dog.jpg",
#"apple" : #"apple.jpeg",
#"clown" : #"clown.gif"
};
To retrieve the image filename for "dog" from this dictionary do this:
NSString *fileName = dictionary[#"dog"];
When a button is clicked you can simply take that value and search into images array to get the matching image name for e-g,
NSString *selValue = #"dog";
for (NSString *obj in imagesArray) {
if ([obj rangeOfString:selValue].location != NSNotFound) {
NSString *imageName = obj;
break;
}
}
This is not the fully working code with your requirement, can be used as an Idea as you have images.
Assuming your word and image are in same index
I have just implemented similar kind of situation with strings named A.jpg, The idea is kept same, You need to transform accordingly.
NSMutableArray *words=[[NSMutableArray alloc]initWithObjects:#"A",#"B",#"C",#"D", nil];
NSMutableArray *images=[[NSMutableArray alloc]initWithObjects:#"A.jpg",#"B.jpg",#"C.jpg",#"D.jpg", nil];
id selectedWord=#"C";//This is storing which word you have selected
id selectedImage=[images objectAtIndex:[words indexOfObject:selectedWord]];//this will store the image
NSLog(#"%#",selectedImage);//now you can display the image in imageview
If words and images are not in anyorder
//words array is of no use, you can simply find which word you selected by extracting before "." , but as I am not aware of exact requirement I have left words array.
NSMutableArray *words=[[NSMutableArray alloc]initWithObjects:#"A",#"B",#"C",#"D", nil];
NSMutableArray *images=[[NSMutableArray alloc]initWithObjects:#"B.jpg",#"D.jpg",#"C.jpg",#"A.jpg", nil];
id selectedWord=#"B";
NSInteger indexOfSelectedWord;
for (NSString *imageName in images) {
if ([[[imageName componentsSeparatedByString:#"."]objectAtIndex:0]isEqualToString:selectedWord]) {
indexOfSelectedWord=[images indexOfObject:imageName];
}
}
id selectedImage=[images objectAtIndex:indexOfSelectedWord];
NSLog(#"%# & %#",selectedWord ,selectedImage);

loading file content to NSArray

I'm using this code to load content to NSArray and it seem to work fine however Instrument to detect leaks point that there is a problem that I can't put my finger on:
- (void) loadPlan: (NSString *) fName
{
short j1;
fName= [NSString stringWithFormat:#"/%#", fName];
[self NewCase];
NSArray *arrayPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDirectory = [arrayPaths objectAtIndex:0];
NSString *filePath = [docDirectory stringByAppendingString:fName];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath];
if (!fileExists) return;
NSString *fileContents = [NSString stringWithContentsOfFile:filePath
encoding:NSUTF8StringEncoding error:nil];
NSArray *chunks = [fileContents componentsSeparatedByString: #"#"];
for (i = 0; i <= 100; i++)
{
InputV[i] = [[chunks objectAtIndex: i+5] doubleValue];
}
...
for (j1 = 0; j1 <= 10; j1++)
{
GroupMode[j1] = [[chunks objectAtIndex: 206+j1] retain];
}
...
}
and on a init method someplace i have:
for (j1 = 0; j1 <= 10; j1++)
{
GroupMode[j1] = [[NSString alloc] initWithFormat:#""];
}
Instrument points to the NSAraay *chunks line code but i'm not sure what's the issue. Do i need to release it at some point ?
I appreciate any help.
In the comments you mention being able to call release. Therefore you are not using ARC and since I noticed you tagged with iphone you are not using GC. This leaves manual memory management.
The problem seems to be that either the chunks array or some chunks themseves are overretained (or underreleased). You are not showing all the code, so it's hard to say.
Make sure you do not retain either of them somewhere else in the code you did not show. Maybe show us the rest of the loadPlan method implementation.
edit: Now that you added more code, I can also expand this answer.
Answer this question: where is the retain call to the chunks matched with a release?
Also what is the declaration of GroupMode? It seems to be just an array of pointers. If so you probably need to release the old value before setting the new one.
Let me try another answer based on what you posted.
I'm assuming GroupMode is an instance variable of some class and is declared like this:
NSString* GroupMode[11];
The second loop in loadPlan should be:
for (j1 = 0; j1 <= 10; j1++)
{
NSString* aChunk = [chunks objectAtIndex: 206+j1];
if ( GroupMode[j1] != aChunk ) {
[GroupMode[j1] release];
GroupMode[j1] = [aChunk retain];
}
}
You should do something similar every time you change an element of GroupMode and you should make sure you release all GroupMode held objects in the dealloc method of that class.
I however suggest you do not use plain arrays and instead switch to using NSArray and/or NSMutableArray.
Take a look at this answer:
"componentsSeparatedByString" Memory leak
The problem is probably that something using the results is over-retaining the stuff from chunks. Instruments is pointing at this line because it's where the memory was first allocated, but it may not be the source of your problem.

Creating dynamic NSMutableDictionary query with multiple values

I'm working on a project and I want to be able to handle some template type messages. The template would contain something like:
"{{user1}} has just created an account"
I then have a data map that would give you a location within the NSMutableDictionary where the data is located:
"activity.message.status"
I then want to be able to query the NSMutableDictionary by splitting up that string, so that it becomes something like:
[[[myDictionary objectForKey:#"activity"] objectForKey:#"message"] objectForKey:#"status"]
I could make something as long as it was consistant on being just 3 strings, but some may be more or less.
Any help would be extremely appreciated.
It's actually much easier than splitting strings into keys. Apples Key-Value-Coding allows exactly what you want.
[myDictionary valueForKeyPath:#"activity.message.status"];
A key path is a string of dot separated keys that is used to specify a sequence of object properties to traverse. The property of the first key in the sequence is relative to the receiver, and each subsequent key is evaluated relative to the value of the previous property.
For example, the key path address.street would get the value of the address property from the receiving object, and then determine the street property relative to the address object.
Key-Value Coding Programming Guide
You would do something like,
NSArray *array = [#"activity.message.status" componentsSeperatedByString:#"."];
Which will create an array containing {activity,message,status).
Now you have your array you can use for querying your dictionary.
[[[myDictionary objectForKey:[array objectAtIndex:0]] objectForKey:[array objectAtIndex:1]] objectForKey:[array objectAtIndex:2]];
Which is equivalent to:
[[[myDictionary objectForKey:#"activity"] objectForKey:#"message"] objectForKey:#"status"];
Hope this helps !
It's not clear to me from your question how we should map user1 to activity.message.status. For now I'll assume you mean that the template might contain a string like "{{activity.message.status}}" and you want to be able to parse that.
Here's one iteration that operates on an NSMutableString that can be looped until no match is found:
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\\{\\{.+?\\}\\}"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSRange matchRange = [regex rangeOfFirstMatchInString:string
options:0 range:NSMakeRange(0, [string length])];
NSRange keyPathRange = NSMakeRange(matchRange.location + 2, matchRange.length - 4);
NSString *keyPath = [string substringWithRange:keyPathRange];
NSString *newSubstring = [myDictionary valueForKeyPath:keyPath];
[string replaceCharactersInRange:matchRange withString:newSubstring];
I haven't tested this code.
How about a (recursive ... cool) category method on NSMutableDictionary like this:
- (void)setObject:(id)object forCompoundKey:(NSString *)compoundKey {
NSArray *keys = [compoundKey componentsSeparatedByString:#"."];
if ([keys count] == 1) {
return [self setObject:object forKey:compoundKey];
}
// get the first component of the key
NSString *key = [keys objectAtIndex:0];
// build the remaining key with the remaining components
NSRange nextKeyRange;
nextKeyRange.location = 1;
nextKeyRange.length = [keys count] - 1;
NSArray nextKeys = [keys subarrayWithRange:nextRange];
NSString *nextKey = [nextKeys componentsJoinedByString:#"."];
NSMutableDictionary *nextDictionary = [NSMutableDictionary dictionary];
[self addObject:nextDictionary forKey:key];
// now the cool part... recursion
[nextDictionary setObject:object forCompoundKey:nextKey];
}
I haven't tested this, but it passes a quick desk check. The objectForCompoundKey: retrieval can be written analogously.

Convert NSString to fetch synthesized information

//COPY THIS CODE IN A FRESH PROJECT!!!
//THIS 2 LINES ARE JUST EXAMPLES, OF VALUES PUSHES OUT A DATABASE
NSString *messagelevel1 = #"45";
NSString *currentlevel = #"1";
NSString *HuidigLevel = currentlevel;
NSDecimalNumber *huidigleveldec = [[NSDecimalNumber alloc] initWithString: HuidigLevel];
float HuidigLevelRek = [huidigleveldec floatValue];
//HERE IS THE PROBLEM
NSString* LevelTotaal=[[NSString alloc] initWithFormat:#"messagelevel%.f",HuidigLevelRek];
NSString*result = LevelTotaal;
NSLog(#"%#",result);
// THE ABOVE RESULT SHOULD RETURN THE SAME VALUE AS THE NEXT (messagelevel1) LINE BUT IT RETURNS ONLY "messagelevel1" AND NOT THE VALUE!
NSLog(#"%#",messagelevel1);
I want the *result string behaves like the *huidiglevel string and fetch some information, but because the LevelTotaal is a NSString, It doesn't fetch this information. I really got no idea where to google for this problem, searching the Developer docs didn't helped either . Maybe you guys can help me out?
Actually the second NSLog returns the value and to first NSLog just returns messagelevel1. To tell you in short ;)
I hope you guys get what I'm saying!
I think what you're trying to do is use variable variables, a system that does not exist in Objective-C. In PHP, you can use variable variables:
$hello = 'abcdef';
$varName = 'hello';
print $$varName; // prints the value of $hello, which is 'abcdef'
Like many things in PHP, this is not really a good way to design software. Instead, consider using something like a NSDictionary, this allows you to give specific data a key.
NSMutableDictionary *aDict = [NSMutableDictionary dictionary];
[aDict setObject:[NSNumber numberWithFloat:4.5] forKey:#"messageLevel1"];
NSString *result = [aDict objectForKey:#"messageLevel1"];
You can obtain the data dynamically, the key can be generated or obtained at runtime.
Edit:
Rather than having variables called messageLevel1, messageLevel2, messageLevel3 ... messageLeveln, just use an array.
NSMutableArray *messageLevels = [NSMutableArray array];
[messageLevels addObject:#"1"];
[messageLevels addObject:#"45"];
[messageLevels addObject:#"123"];
NSString *result = [messageLevels objectAtIndex:HuidigLevelRek];

Creating Arrays from a plist file in iphone SDK 3.3 and up : objective c

I have run into this issue and have put some major time into finding the answer. I am somewhat new to objective c but not to programming.
Here is my question.
I have a plist file with this structure
root {
A (
{songTitle : contents of song},
{songTitle : contents of song}
),
B (
{songTitle : contents of song}
),
C (
{songTitle : contents of song}
),
... kepps going
}
Sorry if the the plist structure is not correct.
Pretty much I have a root dictionary (that is what it comes with) that contains an array of A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,...Z (alphabet)
Each letter of the alphabet array contains 1 or more dictionaries that have a key, value pair of songTitle (this could be any string) as the key and the song lyrics for the value.
My issue here is I need to create an array of all song titles and have been having a rough time trying to find out how to do this. I own 4 books on object c and none of them go into detail about multidimensional arrays and how to access pieces inside them.
I have created an array with all the letters and have created an array that contains the objects from each letter.
Like I stated before I need to find out how to make an array that contains each song title.
If you can help me that would save me a lot of time.
Thanks,
Wes
I am guessing you are suggesting I change my root from a dictionary to an array?
Maybe it might be better to show my code here.
Also I have attached an updated version of my plist file
Sorry seems I cannot add the image here but you can view it
http://www.wesduff.com/images/forum_images/plist_examp.png
So as you can see I have updated the plist file to show the array of letters that each contain multiple dictionaries. Each dictionary has a songTitle and a songLyrics.
How can I write code to get an array of songTitles.
Here is what I have come up with so far
NSString *path = [[NSBundle mainBundle] pathForResource:#"songs" ofType:#"plist"];
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
//This gives me an array of all the letters in alphabetical order
NSArray *array = [[dict allKeys] sortedArrayUsingSelector:#selector(compare:)];
/**
Now I need to find out how to get an array of all songTitles
**/
I am still working on this and looking through what others have written but have not found anything yet.
As the first answer has suggested, should I change the root to an array or keep it as I have it in this plist image I have attached.
Thanks again,
Wes
Ok so I did some more digging and came up with this from the plist file that was included in this picture
http://www.wesduff.com/images/forum_images/plist_examp.png
- (void)viewDidLoad {
//path for plist file
NSString *path = [[NSBundle mainBundle] pathForResource:#"songList" ofType:#"plist"];
//dictionary created from plist file
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:path];
//release the path because it is no longer needed
[path release];
//temp array to hold an array of all alphabetical letters
NSArray *array = [[dict allKeys] sortedArrayUsingSelector:#selector(compare:)];
//assign array to allLetters array
self.allLetters = array;
//Create two mutable arrays for the songArray (could do a little cleaner job of this here)
NSMutableArray *songArray = [[NSMutableArray alloc] init];
NSMutableArray *songTitles = [[NSMutableArray alloc] init];
//Add messy array to songArray then we can work with the songArray (maybe something better to do here)
for(id key in dict)
{
[songArray addObject:[dict objectForKey:key]];
}
//temp array to hold a messy array for all of the songTitles
NSArray *tempArray = [songArray valueForKey:#"songTitle"];
//go through the temparray and clean it up to make one array of all song titles and sort them
for (NSUInteger i = 0; i < [tempArray count]; i++) {
[songTitles addObjectsFromArray:[[tempArray objectAtIndex:i] sortedArrayUsingSelector:#selector(compare:)]];
}
//assign all song titles to our array of songTitles
self.allSongTitles = songTitles;
[dict release];
[allSongTitles release];
[songArray release];
[tempArray release];
[array release];
[super viewDidLoad];
// Uncomment the following line to display an Edit button in the navigation bar for this view controller.
// self.navigationItem.rightBarButtonItem = self.editButtonItem;
}
I am sure there is probably a better way to do this but this is what I have come up with on my own. Thanks
If you have single array with the contents of all the letters, the rest is fairly simple. Iterate through the objects and call the dictionary method allKeys on each one. Each call to allKeys will return an NSArray containing the keys of that specific dictionary, which you can then place into another array.
EDIT
I made a mistake, didn't go deep enough. This is what I would do:
NSString *path = [[NSBundle mainBundle] pathForResource:#"songs" ofType:#"plist"];
NSDictionary plistDict = [NSDictionary dictionaryWithContentsOfFile:path]; //not using alloc and init means this isn't retained, so it will be autoreleased at the end of the method
NSArray *allLetterContents = [plistDict allValues]; // array of arrays, where each element is the content of a 'letter' in your plist (i.e. each element is an array of dictionaries)
NSMutableArray *allSongTitles = [[[NSMutableArray alloc] init] autorelease];
for(NSArray *oneLetterContents in allLetterContents)
{
for(NSDictionary *song in oneLetterContents)
{
[allSongTitles addObject:[song objectForKey:#"songTitle"]]
}
}
return allSongTitles;
This array isn't guaranteed to be sorted alphabetically, so you'll have to call [sortedArrayUsingSelector:] on it.
Reference:
NSMutableArray Class Reference
NSDictionary Class Reference