Bold word of a sentence of NSString in Xcode - ios

I have an issue in display sentence with a bold selected word.
NSString * string = #"Notes on iOS7 going to take a <-lot-> of getting used to!";
I want to print a sentence like this:
"Notes on iOS7 going to take a lot of getting used to!"
A plus that I have this code to select "lot" word. So how to base on this selected to bold the word. This string in this is example. So the range would be different.
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"(?<=<-).*?(?=->)"
options:0 error:&error];
if (regex) {
NSRange rangeOfFirstMatch = [regex rangeOfFirstMatchInString:string options:0 range:NSMakeRange(0, [string length])];
if (!NSEqualRanges(rangeOfFirstMatch, NSMakeRange(NSNotFound, 0))) {
NSString *result = [string substringWithRange:rangeOfFirstMatch];
NSLog(#"%#",result);
} else {
// Match attempt failed
}
} else {
// Syntax error in the regular expression
}
It will be:
Before: Notes on iOS7 going to take a <-lot-> of getting used to!
After: Notes on iOS7 going to take a lot of getting used to!
Thanks in advanced.

You have to use a NSAttributedString for that. Have a look at Any way to bold part of a NSString?

Related

iOS Regular Expression to check whether a NSString starts with g

I am new to Regular Expressions and its usage in iOS .I have a scenario where I have to check whether a NSString starts with 'G' this is my function which returns the bool condition . I am passing the data like this
[self compareStringWithRegex:#"Gmail" withRegexPattern:#".*g"];
-(BOOL) compareStringWithRegex:(NSString *) string withRegexPattern:(NSString *)expression
{
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression options:NSRegularExpressionCaseInsensitive error:&error];
NSTextCheckingResult *match = [regex firstMatchInString:string options:0 range:NSMakeRange(0, [string length])];
if (match){
return YES;
}else{
return NO;
}
}
The problem I am facing is, this function returns true if I give wrong condition . Please help me in this and let me know if my question is not clear .
If you want to use Regular Expressions to check string start with "g" then
replace ".*g" with "^g" it will give you asspected result
[self compareStringWithRegex:#"Gmail" withRegexPattern:#"^g"];
If you really want to use regex the #"(g)+(\\w+)" should work. I tested it on Regex Tester

Is it possible to detect links within an NSString that have spaces in them with NSDataDetector?

First off, I have no control over the text I am getting. Just wanted to put that out there so you know that I can't change the links.
The text I am trying to find links in using NSDataDetector contains the following:
<h1>My main item</h1>
<img src="http://www.blah.com/My First Image Here.jpg">
<h2>Some extra data</h2>
The detection code I am using is this, but it will not find this link:
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
for (NSTextCheckingResult *match in matches)
{
if ([match resultType] == NSTextCheckingTypeLink)
{
NSURL *url = [match URL];
// does some stuff
}
}
Is this a bug with Apple's link detection here, where it can't detect links with spaces, or am I doing something wrong?
Does anyone have a more reliable way to detect links regardless of whether they have spaces or special characters or whatever in them?
I just got this response from Apple for a bug I filed on this:
We believe this issue has been addressed in the latest iOS 9 beta.
This is a pre-release iOS 9 update.
Please refer to the release notes for complete installation
instructions.
Please test with this release. If you still have issues, please
provide any relevant logs or information that could help us
investigate.
iOS 9 https://developer.apple.com/ios/download/
I will test and let you all know if this is fixed with iOS 9.
You could split the strings into pieces using the spaces so that you have an array of strings with no spaces. Then you could feed each of those strings into your data detector.
// assume str = <img src="http://www.blah.com/My First Image Here.jpg">
NSArray *components = [str componentsSeparatedByString:#" "];
for (NSString *strWithNoSpace in components) {
// feed strings into data detector
}
Another alternative is to look specifically for that HTML tag. This is a less generic solution, though.
// assume that those 3 HTML strings are in a string array called strArray
for (NSString *htmlLine in strArray) {
if ([[htmlLine substringWithRange:NSMakeRange(0, 8)] isEqualToString:#"<img src"]) {
// Get the url from the img src tag
NSString *urlString = [htmlLine substringWithRange:NSMakeRange(10, htmlLine.length - 12)];
}
}
I've found a very hacky way to solve my issue. If someone comes up with a better solution that can be applied to all URLs, please do so.
Because I only care about URLs ending in .jpg that have this problem, I was able to come up with a narrow way to track this down.
Essentially, I break out the string into components based off of them beginning with "http:// into an array. Then I loop through that array doing another break out looking for .jpg">. The count of the inner array will only be > 1 when the .jpg"> string is found. I then keep both the string I find, and the string I fix with %20 replacements, and use them to do a final string replacement on the original string.
It's not perfect and probably inefficient, but it gets the job done for what I need.
- (NSString *)replaceSpacesInJpegURLs:(NSString *)htmlString
{
NSString *newString = htmlString;
NSArray *array = [htmlString componentsSeparatedByString:#"\"http://"];
for (NSString *str in array)
{
NSArray *array2 = [str componentsSeparatedByString:#".jpg\""];
if ([array2 count] > 1)
{
NSString *stringToFix = [array2 objectAtIndex:0];
NSString *fixedString = [stringToFix stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
newString = [newString stringByReplacingOccurrencesOfString:stringToFix withString:fixedString];
}
}
return newString;
}
You can use NSRegularExpression to fix all URLs by using a simple regex to detect the links and then just encode the spaces (if you need more complex encoding you can look into CFURLCreateStringByAddingPercentEscapes and there are plenty of examples out there). The only thing that might take you some time if you haven't worked with NSRegularExpression before is how to iterate the results and do the replacing, the following code should do the trick:
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"src=\".*\"" options:NSRegularExpressionCaseInsensitive error:&error];
if (!error)
{
NSInteger offset = 0;
NSArray *matches = [regex matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
for (NSTextCheckingResult *result in matches)
{
NSRange resultRange = [result range];
resultRange.location += offset;
NSString *match = [regex replacementStringForResult:result inString:myHTML offset:offset template:#"$0"];
NSString *replacement = [match stringByReplacingOccurrencesOfString:#" " withString:#"%20"];
myHTML = [myHTML stringByReplacingCharactersInRange:resultRange withString:replacement];
offset += ([replacement length] - resultRange.length);
}
}
Try this regex pattern: #"<img[^>]+src=(\"|')([^\"']+)(\"|')[^>]*>" with ignore case ... Match index=2 for source url.
regex demo in javascript: (Try for any help)
Demo
Give this snippet a try (I got the regexp from your first commentator user3584460) :
NSError *error = NULL;
NSString *myHTML = #"<http><h1>My main item</h1><img src=\"http://www.blah.com/My First Image Here.jpg\"><h2>Some extra data</h2><img src=\"http://www.bloh.com/My Second Image Here.jpg\"><h3>Some extra data</h3><img src=\"http://www.bluh.com/My Third-Image Here.jpg\"></http>";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"src=[\"'](.+?)[\"'].*?>" options:NSRegularExpressionCaseInsensitive error:&error];
NSArray *arrayOfAllMatches = [regex matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
NSTextCheckingResult *match = [regex firstMatchInString:myHTML options:0 range:NSMakeRange(0, myHTML.length)];
for (NSTextCheckingResult *match in arrayOfAllMatches) {
NSRange range = [match rangeAtIndex:1];
NSString* substringForMatch = [myHTML substringWithRange:range];
NSLog(#"Extracted URL : %#",substringForMatch);
}
In my log, I have :
Extracted URL : http://www.blah.com/My First Image Here.jpg
Extracted URL : http://www.bloh.com/My Second Image Here.jpg
Extracted URL : http://www.bluh.com/My Third-Image Here.jpg
You should not use NSDataDetector with HTML. It is intended for parsing normal text (entered by an user), not computer-generated data (in fact, it has many heuristics to actually make sure it does not detect computer-generated things which are probably not relevant to the user).
If your string is HTML, then you should use an HTML parsing library. There are a number of open-source kits to help you do that. Then just grab the href attributes of your anchors, or run NSDataDetector on the text nodes to find things not marked up without polluting the string with tags.
URLs really shouldn't contain spaces. I'd remove all spaces from the string before doing anything URL-related with it, something like the following
// Custom function which cleans up strings ready to be used for URLs
func cleanStringForURL(string: NSString) -> NSString {
var temp = string
var clean = string.stringByReplacingOccurrencesOfString(" ", withString: "")
return clean
}

Using stringByReplacingOccurrencesOfString to take into consideration "words"

My goal is to use stringByReplacingOccurrencesOfString to replace occurrences of words or phrases with replacements. The words and their replacements are found in a dictionary such as that the word or phrases are keys, and their values are their replacements:
{"is fun" : "foo",
"funny" : "bar"}
Because stringByReplacingOccurrencesOfString is literal and disregards "words" in the convention Western language sense, I am running in the trouble where the following sentence:
"He is funny and is fun",
the phrase "is fun" is actually detected twice using this method: first as part of "is funny", and the second as part of "is fun", causing an issue where a literal occurrence is used for word replacement, and not realizing that it is actually part of another word.
I was wondering if there is a way to use stringByReplacingOccurrencesOfString that takes into consideration of wording, and so a phrase like "is funny" can be viewed in its complete self, and not also be viewed as "is funny" where "is fun" detected.
By the way, this is the code I am using for replacement when iterating across all the keys in the dictionary:
NSString *newText = [wholeSentence stringByReplacingOccurrencesOfString:wordKey withString:wordValue options:NSLiteralSearch range:[wholeSentence rangeOfString:stringByReplacingOccurrencesOfString:wordKey]];
iteratedTranslatedText = newText;
Edit 1: Using the suggested solutions, this is what I have done:
NSString *string = #"Harry is fun. Shilp is his fun pet dog";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"\bis fun\b" options:0 error:nil];
if (regex != nil) {
NSTextCheckingResult *firstMatch = [regex firstMatchInString:string options:0 range:NSMakeRange(0, string.length)];
//firstMatch is returning null
if (firstMatch) {
NSRange resultRange = [firstMatch rangeAtIndex:0];
NSLog(#"first match at index:%lu", (unsigned long)resultRange.location);
}
}
However, this is returning firstMatch as null. According to the regex tutorial on word boundaries, this is how to anchor a word or phrase, so I am unsure why its not returning anything. Help is appreciated!
As your comment, you can use NSRegrlarEXPression in your project. For example:
NSString *string = #"He is funny and is fun";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"is fun([^a-zA-Z]+|$)" options:0 error:nil];
if (regex != nil) {
NSTextCheckingResult *firstMatch = [regex firstMatchInString:string options:0 range:NSMakeRange(0, string.length)];
if (firstMatch) {
NSRange resultRange = [firstMatch rangeAtIndex:0];
NSLog(#"first match at index:%d", resultRange.location);
}
}
And to result: first match at index:16

Regex issue in IOS Program

I am trying to get the following regex to work on ios in order to make sure the user is only inputting numbers and a dot. I am not able to get number of matches to be above 0. I have also tried NSRange one as well and that will give me 0 no matter what as well, so my regex is not working, even thought I am pretty sure it should with what I have there. Any suggestions.
The Code I wrote is here with errorRegex is defined in the .h file and regError is defined as well.
errorRegex = [NSRegularExpression regularExpressionWithPattern:#"[^0-9.]*"
options: NSRegularExpressionCaseInsensitive error:&regError];
NSUInteger rangeOfFirstMatch = [errorRegex numberOfMatchesInString:servAmount1TF.text
options:0 range:NSMakeRange(0, [servAmount1TF.text length])];
Why not use stock-standard c's regex.h ?
See an example here:
http://cboard.cprogramming.com/c-programming/117525-regex-h-extracting-matches.html
And more information here:
https://stackoverflow.com/a/422159/1208218
errorRegex is of type NSRegularExpression, but the error is of type UIButtonContent. This has all the halmarks of a memory error. Something in your code not going though a proper retain/release cycle.
I got a unit test to work with the expression #"[^0-9.]+"
- (void)testRE
{
NSError *regError = nil;
NSRegularExpression *errorRegex;
NSString *string;
NSUInteger count;
errorRegex = [NSRegularExpression regularExpressionWithPattern:#"[^0-9.]+"
options: NSRegularExpressionCaseInsensitive
error:&regError];
STAssertNil(regError, nil);
string = #"00.0";
count = [errorRegex numberOfMatchesInString:string
options:0
range:NSMakeRange(0, [string length])];
STAssertEquals(count, 0U, nil);
string = #"00A00";
count = [errorRegex numberOfMatchesInString:string
options:0
range:NSMakeRange(0, [string length])];
STAssertEquals(count, 1U, nil);
}
NSRegularExpression *errorCheckRegEx = [[NSRegularExpression alloc] initWithPattern:#"\\b^([0-9]+(\\.)?[0-9]*)$|^([0-9]*(\\.)?[0-9]+)$|^[0-9]*$|^([0-9]*(\\/)?[0-9]*)$\\b" options:NSRegularExpressionCaseInsensitive error:nil];
[match setArray: [errorCheckRegEx matchesInString:servAmount1TF.text options:0 range:NSMakeRange(0, [servAmount1TF.text length])]];
I figured out what I needed to do when I could finally get back to it so if anyone was interested this is what I came up with. The \b is just what ios uses in their regexp which is kind of dumb, but it will not work without that so I leave it there when it doesn't feel natural to do especially after ruby's example. This regular expression will get fractions, decimals -> .3; 2.3; 2; and does it from the front to end of the line. What I think might have been happening was the fact that I was not using the \b and also not matching correctly, which is the second line. Either way it works great now. Thanks for the help.

Replace occurences of string that contains any number

Say I have a string that contains a control code "\f3" (yes it is RTF). I want to replace that control code with another string. At the moment I am using [mutableString replaceOccurrencesOfString:#"\f3" withString:#"replacement string" options:0 range:NSMakeRange(0, [mutableString length])];
This works fine, however sometimes the code can be "\f4" or even "\f12" for example. How do I replace these strings? I could use replaceOccurrencesOfString for each, but the better way to do it is using wildcards, as it could be any number.
Regular expressions would do it.
Take a look at NSRegularExpression (iOS >= 4) and this page for how regular expressions work.
You will want something like:
// Create your expression
NSError *error = nil;
NSRegularExpression *regex =
[NSRegularExpression regularExpressionWithPattern:#"\\b\f[0-9]*\\b"
options:NSRegularExpressionCaseInsensitive
error:&error];
// Replace the matches
NSString *modifiedString = [regex stringByReplacingMatchesInString:string
options:0
range:NSMakeRange(0, [string length])
withTemplate:#"replacement string"];
WARNING : I've not tested my regaular expression and I'm not that great at getting them right first time; I just know that regular expressions are the way forward for you and it has to look something like that ;)

Resources