Scripting Bridge objective-c PagesWord - objective-c

I'm trying to modify an existing Pages document from within my application using the Scripting Bridge. I've followed all steps mentioned in the documentation: I created a header file and thoroughly examined it, but I just can't figure out how how to do this.
I'm basically trying to do a search an replace: I've got a list of strings and I want to replace some search values with those strings. The problem is that I just can't figure out how the PagesWord class works. I just want to get a string from it and it compare it to my search value. I currently have to following code:
PagesApplication *pages = [SBApplication applicationWithBundleIdentifier:#"com.apple.iWork.Pages"];
PagesDocument *document = [pages open:inputURL];
PagesText *bodyText = [document bodyText];
SBElementArray *words = [bodyText words];
NSLog([NSString stringWithFormat:#"%d words.", [words count]]);
for (PagesWord *word in [bodyText words]) {
NSLog((NSString *)word);
}
Everything works well until the last 3 rows: the correct Pages document is opened and the word count is logged, but the string isn't: I just see exception messages. I also tried to work with the properties of PagesWord, but I have the same problems then...
Can anyone help me?

To replace the word i use:
for (PagesWord *word in [bodyText words]) {
[word select];
[[document selection] setTo:#"my new value"];}

Related

Removing text from NSString between "#" and ":" while keeping the text after it

So I'm reading the most recent tweet from a twitter bot and assigning it to a string, but sometimes it tweets directly to users. Here's an example of what that might look like.
NSString tweet = #("#user hey heres my message: BLah blah with symbols!");
//part I want to keep is: " BLah blah with symbols!"
//or it could end up being
NSString tweet = #("#otheruser my msg is: Wow heres some more blah: and a second colon");
//part I want to keep is: " Wow heres some more blah: and a second colon"
I want to always remove the first part that talks to the user, while keeping the message on the end. There are too many different messages to use "stringByReplacingOccurrencesOfString"
I don't want to use "exlude-replies" from the twitter API because this bot is very popular and that would require fetching up to 100 since "count" applies before
any idea how I could do this? I think it has something to do with regular expressions, but I haven't ever used them before or been able to get one working how I want. I would really appreciate the help from anyone whos comfortable with regex
edit: also if a regex won't work for this case, id accept an explanation of the limitation preventing that :)
The easiest solution that I can think of is to create an NSMutable array, by using the NSString function componentsSeparatedBy:#":", and simply remove the first element.
NSMutableArray *tweetArray = [[NSMutableArray alloc] initWithArray: [tweet componentsSeparatedByString:#":"]];
[tweetArray removeObjectAtIndex:0];
Your issue with a colon appearing at random afterwards can be fixed by joining the pieces back together again.
tweet = [tweetArray componentsJoinedByString:#":"];
Edit: Fix an error pointed out by user 'maddy'
You'll have to stick this code in an if statement so that it does not execute in tweets that have a colon normally. You can use the fact that it always begins with #user however.
if ([tweet characterAtIndex:0] == '#' && [tweet characterAtIndex:1] != ' '){
NSMutableArray *tweetArray = [[NSMutableArray alloc] initWithArray: [tweet componentsSeparatedByString:#":"]];
[tweetArray removeObjectAtIndex:0];
tweet = [tweetArray componentsJoinedByString:#":"];
}
You can also use this.
NSString *myString = #"#username is me: by using this as sample text";
NSRange range = [myString rangeOfString:#":"];
NSString *newString= [myString substringFromIndex:range.location];
NSLog(#"New String is : %#", newString);

Parsing text from one array into another array in Objective C

I created an array called NSArray citiesList from a text file separating each object by the "," at the end of the line. Here is what the raw data looks like from the text file.
City:San Jose|County:Santa Clara|Pop:945942,
City:San Francisco|County:San Francisco|Pop:805235,
City:Oakland|County:Alameda|Pop:390724,
City:Fremont|County:Alameda|Pop:214089,
City:Santa Rosa|County:Sonoma|Pop:167815,
The citiesList array is fine (I can see count the objects, see the data, etc.) Now I want to parse out the city and Pop: in each of the array objects. I assume that you create a for loop to run through the objects, so if I wanted to create a mutable array called cityNames to populate just the city names into this array I would use this kind of for loop:
SMutableArray *cityNames = [NSMutableArray array];
for (NSString *i in citiesList) {
[cityNames addObject:[???]];
}
My question is what is what query should I use to find just the City: San Francisco from the objects in my array?
You can continue to use componentsSeparatedByString to divide up the sections and key/value pairs. Or you can use an NSScanner to read through the string parsing out the key/value pairs. You could use rangeOfString to find the "|" and then extract a range. So many options.
Many good suggestions in the answers here in case you really want to construct an algorithm to parse the string.
As an alternative to that, you can also look at it as a problem of declaring the structure of the data and then just have the system do the parsing. For a case like yours, regular expressions will do that nicely. Whether you prefer to do it one way or the other is largely a question of taste and coding standards.
In your specific case (if the city name is all you need to extract from the string), then also notice that there is a bit of a shortcut available that will turn it into a one-line solution: Match the whole string, define a single capture group and substitute that one to make a new string:
NSString *city = [i stringByReplacingOccurrencesOfString: #".*City:(.*?)\\|.*"
withString: #"$1"
options: NSRegularExpressionSearch
range: NSMakeRange(0, row.length)];
The variable i is the same that you have defined in your for-loop, i.e. a string containing a string representing a line in your input file:
City:San Jose|County:Santa Clara|Pop:945942,
I have added the initial .* to make the pattern robust to future new fields added to the rows. You can remove it if you don't like it.
The $1 in the substitution string represents the first capture group, i.e. the parenthesis in the regex pattern. In this specific case, the substring containing the city name. Had there been more capture groups, they would have been named $2-$9. You can check the documentation on NSRegularExpression and NSString if you want to know more.
Regular expressions are a topic all of their own, not confined to the Cocoa, although all platforms use regex implementations with their own idiosyncrasies.
You want to use componentsSeparatedByString: as below. (These lines do no error checking)
NSArray *fields = [i componentsSeparatedByString:#"|"];
NSString *city = [[[fields objectAtIndex:0] componentsSeparatedByString:#":"] objectAtIndex:1];
NSString *county = [[[fields objectAtIndex:1] componentsSeparatedByString:#":"] objectAtIndex:1];
If you can drop the keys, and a couple delimiters like this:
San Jose|Santa Clara|945942
San Francisco|San Francisco|805235
Oakland|Alameda|390724
Fremont|Alameda|214089
Santa Rosa|Sonoma|167815
Then you can simplify the code (still no error checking):
NSArray *fields = [i componentsSeparatedByString:#"|"];
NSString *city = [fields objectAtIndex:0];
NSString *county = [fields objectAtIndex:1];
for (NSString *i in citiesList) {
// Divide each city into an array, where object 0 is the name, 1 is county, 2 is pop
NSArray *stringComponents = [i componentsSeparatedByString:#"|"];
// Remove "City:" from string and add the city name to the array
NSString *cityName = [[stringComponents objectAtIndex:0] stringByReplacingCharactersInRange:NSMakeRange(0, 5) withString:#""];
[cityNames addObject:cityName];
}

getting NSArray length/count - Objective C

Well I've looked at similar problems over the site but haven't reached a solution thus far so I must be doing something wrong.
Essentially, I am importing a text file, then splitting each line into an element of an array. Since the text file will be updated etc.. I won't every know the exact amount of lines in the file and therefore how many elements in the array. I know in Java you can do .length() etc.. and supposedly in Objective C you can use 'count' but i'm having no luck returning the length of my array... suggestions?
NSString *filePath = [[NSBundle mainBundle] pathForResource:#"allshows"
ofType:#"txt"];
NSString *fileString = [NSString stringWithContentsOfFile:filePath];
NSArray *lines = [fileString componentsSeparatedByString:#"\n"];
NSUInteger *elements = [lines count];
NSLog(#"Number of Shows : ", elements);
and what is being output is NOTHING. as in "Number of Shows : " - blank, like it didn't even count at all.
Thank you for any help!
You're missing the format string placeholder. It should be:
NSLog(#"Number of shows: %lu", elements);
You need to use a format specifier to print an integer (%d):
NSLog(#"Number of Shows : %d", elements);
Looking at your other post, it seems like you are a Java developer. In Java's System.out, you just append the variables. In Objective-C, I suggest you look at "print format specifiers". Objective-C uses the same format.

Multiple Substrings in String

I´m working on an app that displays 6 pictures from a website. These pictures change over time so I extracted the sourcecode of said website and managed to pull the first of the 6 pictures with this code:
NSError *error = nil;
NSString *deviantStringPopular;
deviantStringPopular = [NSString stringWithContentsOfURL:[NSURL URLWithString:#"http://browse.deviantart.com/?order=24"]
encoding:NSISOLatin1StringEncoding
error:&error];
NSString *popularContent;
NSRange popularURLRange1 = [deviantStringPopular rangeOfString:#"super_img=\""];
NSRange popularURLRange2 = [deviantStringPopular rangeOfString:#"\" super_w"];
int lengt = popularURLRange2.location - popularURLRange1.location - popularURLRange1.length;
int location = popularURLRange1.location + popularURLRange1.length;
NSRange endRange;
endRange.location = location;
endRange.length = lengt;
popularContent = [deviantStringPopular substringWithRange:endRange];
NSLog(#"%#", popularContent);
The problem is, the other 5 images' URLs are between the same substrings as the first one.
So is it possible that the first image's URL is ignored once the it´s loaded successfully and the second one loads and is stored under a different variable and so on?
thanks in advance
To get 6 URLs from the string and load them into different variables, you could try using a loop. With each iteration, after the substring is found and stored into a variable, make a range from the beginning of the string up to the end of the substring you found. You can use stringByReplacingCharactersInRange to erase the part of the string already searched so that the next time you search the string for the substring, it will find the next URL.
An easier solution may be to use RegexKit, if you know how to use RegEx's. Then each URL could just be a capture group.

IPhone Navigation-Based Application Model

I am making a Navigation-Based Application for the IPhone and I start off with a big list of names (about 100) and I was wondering what would be the quickest and most efficient way to alter the content according to what name the user tapped on in the list.
Right now I change the content according to what the title is like this:
NSString *comparisonString = #"Bill Clinton";
NSString *comparisonString2 = #"Bob Dole";
if (self.title == comparisonString) {
NSString *alterString = [NSString stringWithFormat: #"He is a democrat from North Carolina "];
[appDelegate setModelData:alterString];
}
else if (self.title == comparisonString2) {
NSString *alterString = [NSString stringWithFormat: #"He was born into a family in New York City... "];
[appDelegate setModelData:alterString];
}
would this be the best way to do this? Seems like a lot of code would be repeated. I am brand new to Objective-C and developing for the IPhone, any advice will help me. Thank you!
What you've written so far in those two conditions is equivalent to this (with no if statement):
NSString *alterString = [NSString stringWithFormat: #"Content for %#!", self.title];
[appDelegate setModelData:alterString];
Hope that helps.
All you are doing is changing that same part of the string in both the if and else statements (and presumably more else statements later)
EDIT
ok, looking now at the edited question, you basically have a look up table now. So self.title is the key and you want to use that to lookup another string.
One way to do this is to create a plist with a dictionary that maps each name to a string. Then load that plist and look up the name from there. Something like this:
NSDictionary* people = [NSDictionary dictionaryWithContentsOfFile:pathToThePlist];
NSString *content = [people objectForKey:name];
(BTW, right now you are using '==' for string comparison, you want to use -[NSString isEqualToString:] for that in the future.