NSRegularExpression with callback - iphone

I have to make dynamic replacement into HTML files on iOS App.
It s about localisation.
in the HTML files, I ve got things like : LANG(183) which must be turned into "a localized string"
I was looking at stringByreplacingMatchesInString but cant find any version that accept a callback function? do I miss something ?

You could use a block-based matching method of NSRegularExpression:
NSMutableString *newString = [htmlString mutableCopy];
[regex enumerateMatchesInString:htmlString
options:0
range:NSMakeRange(0, [htmlString length])
usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) {
// [result range] is the matching range.
// Do something with newString.
}
];
(As far as I know) you must not modify htmlString inside the block. Therefore you have to create a mutable copy first which you can modify in the block.
Of course, you have to keep track of changes in the length of newString, because the matching range will always refer to htmlString.

Related

How can I find a dynamic number in a long NSString?

I have a very big NSString, which holds around 1500 characters in it. In this string I need to extract a phone number, which may change frequently, as it is a dynamic data. The phone number will be in the format of 251-221-2000, how can I extract this?
Check out this previous question on regular expressions and NSString.
Search through NSString using Regular Expression
In your case an appropriate regular expression would be #"\\d{3}-\\d{3}-\\d{4}".
This sounds like a perfect candidate for a regular expression. You can use the NSRegularExpression class to achieve this. You can test your regular expression at http://www.regextester.com
NSString *yourString = #"Your 1500 characters string ";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"\d{3}-\d{3}-\d{4}"
options:NSRegularExpressionCaseInsensitive
error:&error];
[regex enumerateMatchesInString:yourString options:0 range:NSMakeRange(0, [yourString length]) usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
// your code to handle matches here
}];
Let me know it is working or not.

NSRegularExpression not getting exact text

I have a string like:
<book>MyBook</book><value>myValue</value>
Now I want to get the text "myValue" out of this string. I want to use NSRegularExpression to do this. I tried this:
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(<book>MyBook</book>\\s*<value>).*?(</value>)"
options:NSRegularExpressionCaseInsensitive
error:&error];
NSArray *textArray = [regex matchesInString:myData options:0 range:NSMakeRange(0, [myData length])];
NSTextCheckingResult * result = [rege firstMatchInString:myData
options:0
range:NSMakeRange(0, [myData length])];
The result is:
<book>MyBook</book><value>myValue</value>
So I get the whole string, but I only want "myValue". How can I do this? What am I missing here?
Thanks in advance!
That happens because you wrote a regex that matches the entire string. I'd reckon that writing a regex that will only match the myValue part of the string is way too complicated to be bothered with (due to the fact that you've got MyBook string that will probably match anything myValue does).
I'd recommend not using regex for this, as they are not intended for the use you've described here. If you don't want to use any XML deserialization, you could use a NSScanner or any of the NSString class methods which will yield a simpler, and easier code to maintain.
For example, using an NSScanner and a few other methods:
NSString *stringToBeScanned = #"<book>MyBook</book><value>myValue</value>";
NSString *myValue;
NSScanner *scanner = [NSScanner scannerWithString:stringToBeScanned];
[scanner scanUpToString:#"<value>" intoString:nil];
// After the above, we've got "<value>myValue</value>" left to scan
[scanner scanUpToString:#"</value>" intoString:&myValue];
// We ended up with a "<value>myValue" type of a string
// This will trim the remaining of the string we don't need
myValue = [myValue stringByReplacingOccurrencesOfString:#"<value>" withString:#""];
The above could probably be written better and I might have made a mistake or two writing it out my head, but the principle should work.

How to find twitter handles in a NSString

If I had the following:
NSString *tweet = #"Shoutout to #somebody and #somebodyElse for your help on this one #shoutouts";
How would i go about finding the range of the twitter handles (eg #somebody)??
I want to make them bold in my Attributed String which is the next step.
Bonus points if you can help me find the # hash tags as well, but I assume its the same algorithm.
NSRegularExpression is your friend.
Use NSRegularExpression class,
http://developer.apple.com/library/ios/#documentation/Foundation/Reference/NSRegularExpression_Class/Reference/Reference.html
Than trying using this online tool to build Regex,
http://www.gskinner.com/RegExr/
I tried this and it seems like you can build a good one,
SAMPLE CODE - NOT TESTED
NSString *yourString = #"Shoutout to #somebody and #somebodyElse for your help on this one #shoutouts";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression
regularExpressionWithPattern:#"\#\S+|#\S+"
options:NSRegularExpressionCaseInsensitive
error:&error];
[regex enumerateMatchesInString:yourString options:0 range:NSMakeRange(0, [yourString length]) usingBlock:^(NSTextCheckingResult *match, NSMatchingFlags flags, BOOL *stop){
// your code to handle matches here
}];
About test in online tool!
Good luck!

iPhone: regular expression and text input validation in UITextField is failing

I have the following code thats supposed to take the input entered into a UITextField and validate it. It doesn't seem to be working and Im a little confused as to why.
Could someone give me some advice please?
NSString *const regularExpression = #"([0-9a-zA-Z\\s]{1,6})";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regularExpression options:NSRegularExpressionCaseInsensitive error:&error];
if (error)
{
NSLog(#"error %#", error);
}
NSUInteger numberOfMatches =
[regex numberOfMatchesInString:s options:0 range:NSMakeRange(0, [s length])];
NSLog(#"index = %d", i);
NSLog(#"Value of TextField = %#", s);
NSLog(#"Regular expression is = %#", regularExpression);
if (numberOfMatches <= 0)
{
NSLog(#"Failed regex test ");
}
This string should fail the regular expression test :"Einxnkxkd Xnckck"
But it passed.
im not sure how and why...
Anything obvious Im missing here?
Thanks
The method numberOfMatchesInString: searches for matches within the string. It does not test your pattern against the entire string.
It is passing because the pattern ([0-9a-zA-Z\\s]{1,6}) is matching at least the first six letters of your test string Einxnkxkd Xnckck yielding Einxnk. In fact, I can find lots of matches: E, Ein, inx, etc.
If you want to make sure the whole string matches the pattern, use ^ to indicate the beginning of the string and $ to mark the end of it, so that your pattern becomes ^([0-9a-zA-Z\\s]{1,6})$.
If you want to limit the expression to exactly the string, you need to wrap the expression in ^..$:
NSString *const regularExpression = #"^([0-9a-zA-Z\\s]{1,6})$";
Edit: Use the RegEx Air app to test, it's pretty handy (or any other reg exp tester)

URL-encoding and HTML-encoding NSStrings

Is their a method to encode/decode HTML and URL (in Xcode, using Objective-C)?
[NSString stringWithContentsOfFile:<#(NSString *)path#> encoding:<#(NSStringEncoding)enc#> error:<#(NSError **)error#>]
This doesn't seem to work how i expected. I thought it will convert special characters like "<" to equivalent HTML entities i.e. "<" in this case.
Here's a reference to the w3school link related to this topic (general):
HTML URL Encoding Reference
HTML Entities Reference
Thanking in anticipation.
Returns a representation of the receiver using a given encoding to determine the percent escapes necessary to convert the receiver into a legal URL string.
- (NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)encoding
and
Returns a new string made by replacing in the receiver all percent escapes with the matching characters as determined by a given encoding.
- (NSString *)stringByReplacingPercentEscapesUsingEncoding:(NSStringEncoding)encoding
The method you cite reads a file from disk with a given character encoding (such as UTF-8 or ASCII). It has nothing to do with URL or HTML escaping.
If you want to add URL percent escapes, you want this method:
[myString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
Make sure you read the documentation about this method, because there are certain subtleties about what it escapes and what it leaves alone. In some cases, you may have to use the more complex, but more flexible, CFURLCreateStringByAddingPercentEscapes(). (If you do, note that you can cast CFStringRef to NSString * and vice versa.)
There's nothing built in that I know of to do XML/HTML-style entity escaping, but this function ought to handle the basics:
NSString * convertToXMLEntities(NSString * myString) {
NSMutableString * temp = [myString mutableCopy];
[temp replaceOccurrencesOfString:#"&"
withString:#"&"
options:0
range:NSMakeRange(0, [temp length])];
[temp replaceOccurrencesOfString:#"<"
withString:#"<"
options:0
range:NSMakeRange(0, [temp length])];
[temp replaceOccurrencesOfString:#">"
withString:#">"
options:0
range:NSMakeRange(0, [temp length])];
[temp replaceOccurrencesOfString:#"\""
withString:#"""
options:0
range:NSMakeRange(0, [temp length])];
[temp replaceOccurrencesOfString:#"'"
withString:#"&apos;"
options:0
range:NSMakeRange(0, [temp length])];
return [temp autorelease];
}
To do HTML/XML entity encoding, you can use a CFMutableString function:
NSString *result = .....;
CFStringTransform((CFMutableStringRef)result, NULL, kCFStringTransformToXMLHex, false);
By setting the last parameter of CFStringTransform to true, it should work for decoding (hex) entities as well.
Use CFStringTransform for HTML entity encoding/decoding:
CFStringTransform((CFTypeRef)yourMutableString, NULL, CFSTR("Any-Hex/XML"), FALSE );
You need to use the ICU transform "Any-Hex/XML". kCFStringTransformToXMLHex isn't aggressive enough.