How to replace strings using regex in objective C? - ios

I have a string that sometimes contains strings like: #"[id123123|Some Name]"
What I have to do, is to simply replace it to "Some Name"
For example I have string: Some text lalala blabla [id123|Some Name] bla bla bla
And I need to get: Some text lalala blabla Some Name bla bla bla
The question is how to? My mind tells me that I can do this with NSRegularExpression

Look into stringByReplacingOccurrencesOfString:withString:options:range:. The options: allow the search string to be a regular expression pattern.

Not an Objective C person, but judging from this previous SO post, you could use a regex like so:
NSString *regexToReplaceRawLinks = #"\\[.+?\\|(.+?)\\]";
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:regexToReplaceRawLinks
options:NSRegularExpressionCaseInsensitive
error:&error];
NSString *string = #"[id123|Some Name]";
NSString *modifiedString = [regex stringByReplacingMatchesInString:string
options:0
range:NSMakeRange(0, [string length])
withTemplate:#"$1"];
This should match the string you are using and place the name in a group. You then replace the entire string [id123|Some Name] with Some Name.

Regex101
(\[[^|]+|([^\]]+]))
Description
\[ matches the character [ literally
[^|]+ match a single character not present in the list below
Quantifier: + Between one and unlimited times, as many times as possible, giving back as needed [greedy]
| the literal character |
\| matches the character | literally
1st Capturing group ([^\]]+])
[^\]]+ match a single character not present in the list below
Quantifier: + Between one and unlimited times, as many times as possible, giving back as needed [greedy]
\] matches the character ] literally
] matches the character ] literally
In capture group 1 is the thing you want to replace with what is in capture group 2. enjoy.

Related

Coloring Text within $ - NSString

pattern = #"(\\$.*?\\$)";
regex = [NSRegularExpression regularExpressionWithPattern:pattern options:0 error:&error];
matches = [regex matchesInString:self options:0 range: searchedRange];
for (NSTextCheckingResult* match in matches) {
[string addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:[match range]];
}
I'm using the above code to color text inbetween two dollar signs. So the hello world text in the following string would be colored blue, with the dollar signs removed:
#"This won't be blue. $hello world$. This won't be blue";
Now, however, I want a single dollar sign to not be colored blue. I only want the pattern to match when the first dollar sign is succeeded by a character in a-zA-Z0-9 and likewise the second dollar sign should be preceded by a character in a-zA-Z0-9. How can I do this?
Move the capturing group a bit after the first $ and before the last $, and use matchAtIndex:1 to only get Group 1 value:
pattern = #"\\$([A-Za-z0-9].*?)(?<=[A-Za-z0-9])\\$";
^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^^
And
[string addAttribute:NSForegroundColorAttributeName value:[UIColor blueColor] range:[match matchAtIndex:1]];
Pattern details:
\\$ - a literal $
([A-Za-z0-9].*?) - a letter or digit followed with 0+ any chars but a newline as few as possible upto the first
(?<=[A-Za-z0-9])\\$ - $ that is preceded with a letter or digit
If you only need to make sure a digit or letter appears after the first $, use
pattern = #"\\$\\b(?!_)(.*?)\\$";
Where the first $ can be followed with letters or digits, but not _.
You probably just need to adjust your regular expression a little.
A really good resource for this is http://regexr.com/ because it lets you try out new expressions live.
In this specific case you probably want:
pattern = #"(\\$.+\\$)";
The difference between * and + is that + requires at least 1 character. Also the ? was not doing anything because the * by default makes something optional.
I believe this does what I want pattern = #"(\\$[a-zA-Z0-9]{1}.*\\$)";
Thanks to Tristan for the resource

One uppercase letter validation regex

I am working on a regex validation for an alphanumeric character with a length of 4 but contains only one Uppercase letter.
This is the code I have:
NSRegularExpression *expression = [NSRegularExpression regularExpressionWithPattern:#"(?=.*[0-9])(?=.*[A-Z])[a-zA-Z0-9]{4}" options:NSRegularExpressionCaseInsensitive error:&error];
However, it does not perform the check correctly. How can I do it?
Change your pattern like this,
#"^(?=.*[0-9])(?=[^A-Z]*[A-Z][^A-Z]*$)[a-zA-Z0-9]{4}$"
I think this would be enough for you
#"^(?=.*\\d)(?=.*[A-Z]).{4}$"
Or if you want to give minimum and maximum length then use below snippet
#"^(?=.*\\d)(?=.*[A-Z]).{4,15}$"
Here 4 would be the minimum length and 15 would be maximum length for your string
If you need to differentiate upper- and lowercase letters, you need to remove NSRegularExpressionCaseInsensitive option. It removes the differentiation between the lower and upper case.
Once you remove it, the following regex (if you need to support Unicode letters):
#"\\A(?=\\D*\\d)(?=\\P{Lu}*\\p{Lu}\\P{Lu}*\\z)[\\p{L}\\d]{4}\\z"
Or just ASCII:
#"\\A(?=\\D*\\d)(?=[^A-Z]*[A-Z][^A-Z]*\\z)[A-Za-z\\d]{4}\\z"
See another regex demo
NSRegularExpression *expression = [
NSRegularExpression regularExpressionWithPattern:#"\\A(?=\\D*\\d)(?=[^A-Z]*[A-Z][^A-Z]*\\z)[A-Za-z\\d]{4}\\z"
options:0
error:&error];
Regex breakdown:
\A - unambigous start of string
(?=\D*\d) - check if there is at least 1 digit after 0 or more non-digits (\D*)
(?=\P{Lu}*\p{Lu}\P{Lu}*\z) - check if there is ONLY 1 uppercase letter (\p{L}) in-between 0 or more any characters other than uppercase letters (\P{Lu})
[\p{L}\d]{4} - exactly 4 characters that are either a letter (lower- or uppercase) or a digit.
\z - match unambigous end of string.
IDEONE demo resulting in "yes":
NSString * s = #"e3Df";
NSString * rx = #"\\A(?=\\D*\\d)(?=[^A-Z]*[A-Z][^A-Z]*\\z)[A-Za-z\\d]{4}\\z";
NSPredicate * predicat = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", rx];
if ([predicat evaluateWithObject:s]) {
NSLog (#"yes");
}
else {
NSLog (#"no");
}

Regular expression to extract text line by line

Is it possible to make a regex check line by line of the data? So if I have the text as:
#EXTINF:-1 tvg-name="seedocs" tvg-logo="RT",RT
#http://odna.octoshape.net/f3f5m2v4/cds/ch5_320p/chunklist.m3u8
#http://odna.octoshape.net/f3f5m2v4/cds/ch5_720p/chunklist.m3u8
http://rt.ashttp14.visionip.tv/live/rt-global-live-HD/playlist.m3u8
#EXTINF:-1 tvg-name="hsn" tvg-logo="hsn",HSN TV
rtsp://hsn.mpl.miisolutions.net:1935/hsn-live01/_definst_/mp4:420p500kB31
I want to remove all the text start from: #http:....
So that i have used the code as below:
To get the match data:
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"((#EXTINF.*\r\n)(.*))+(http|https)://((\\w)*|([0-9]*)|([-|_])*\r\n)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+" options:NSRegularExpressionCaseInsensitive error:&error];
To Remove text start from #http...:
NSRegularExpression *regexName = [NSRegularExpression regularExpressionWithPattern:#"#.*$" options:NSRegularExpressionCaseInsensitive error:&error];
This will give the output as below in the log:
#EXTINF:-1 tvg-name="seedocs" tvg-logo="RT",RT
which mean, i could not retrieve the value of:
http://rt.ashttp14.visionip.tv/live/rt-global-live-HD/playlist.m3u8
my output should be something like this:
#EXTINF:-1 tvg-name="seedocs" tvg-logo="RT",RT
http://rt.ashttp14.visionip.tv/live/rt-global-live-HD/playlist.m3u8
Please somebody help me to sortout this issue.
It is possible to construct REs which match multiple lines, but doing so can be a challenge - both to you and the RE engine. You are usually better off matching single lines; for example you could match lines starting with #http, include the line terminator, and replace each such match with nothing.
However if you are doing line-by-line processing you might be even better off using componentsSeparatedByString: to first break your input into lines, and then processing each line - say by dropping those which start with #http (use hasPrefix:).
HTH
Checkout the following code to do this: I want to remove all the text start from: #http:....
NSMutableString *finalString = string.mutableCopy;
[string enumerateLinesUsingBlock:^(NSString *line, BOOL *stop) {
if ([line hasPrefix:#"#http"]) {
[finalString replaceOccurrencesOfString:line withString:#"" options:NSCaseInsensitiveSearch range:NSMakeRange(0, finalString.length)];
}
}];

iOS - NSString regex match

I have a string for example:
NSString *str = #"Strängnäs"
Then I use a method for replace scandinavian letters with *, so it would be:
NSString *strReplaced = #"Str*ngn*s"
I need a function to match str with strReplaced. In other words, the * should be treated as any character ( * should match with any character).
How can I achieve this?
Strängnäs should be equal to Str*ngn*s
EDIT:
Maybe I wasn't clear enough. I want * to be treated as any character. So when doing [#"Strängnäs" isEqualToString:#"Str*ngn*s"] it should return YES
I think the following regex pattern will match all non-ASCII text considering that Scandinavian letters are not ASCII:
[^ -~]
Treat each line separately to avoid matching the newline character and replace the matches with *.
Demo: https://regex101.com/r/dI6zN5/1
Edit:
Here's an optimized pattern based on the above one:
[^\000-~]
Demo: https://regex101.com/r/lO0bE9/1
Edit 1: As per your comment, you need a UDF (User defined function) that:
takes in the Scandinavian string
converts all of its Scandinavian letters to *
takes in the string with the asterisks
compares the two strings
return True if the two strings match, else false.
You can then use the UDF like CompareString(ScanStr,AsteriskStr).
I have created a code example using the regex posted by JLILI Amen
Code
NSString *string = #"Strängnäs";
NSError *error = nil;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[^ -~]" options:NSRegularExpressionCaseInsensitive error:&error];
NSString *modifiedString = [regex stringByReplacingMatchesInString:string options:0 range:NSMakeRange(0, [string length]) withTemplate:#"*"];
NSLog(#"%#", modifiedString);
Output
Str*ngn*s
Not sure exactly what you are after, but maybe this will help.
The regular expression pattern which matches anything is. (dot), so you can create a pattern from your strReplaced by replacing the *'s with .'s:
NSString *pattern = [strReplaced stringByReplacingOccurencesOfString:#"*" withString:"."];
Now using NSRegularExpression you can construct a regular expression from pattern and then see if str matches it - see the documentation for the required methods.

NSRegularexpression multiline and stack

I can't find a regular expression having balanced tags, one for opening and one for closing.
Tags must enclose multi lines text; and tags are dynamic, not defined at compile time
I can't match the closing tag corresponding to the opening tag, for instance {{home}} -> {{/home}} and {{hello}} -> {{/hello}}; it match {{home}} to {{/hello}}
Any help will be greatly appreciated
Any help will be greatly appreciated
gregoire
ps : I commented non working regexp
NSString * string;
NSError* error = nil;
NSRegularExpression* regex;
NSArray* matches;
string =
#" The {{demo}}following tables describe the {{/demo}}character expressions"
" used by the regular expression to match patterns within "
" a string,{{home}} the pattern operators that specify how many"
" times a pattern is matched and additional matching"
" restrictions, and the last {{/home}}table specifies flags"
" that can be included in the regular ";
regex = [NSRegularExpression regularExpressionWithPattern:
#"\\{\\{demo\\}\\}"
"(.*)?"
"\\{\\{(//|/demo)\\}\\}"
options:NSRegularExpressionDotMatchesLineSeparators
error:&error];
// regex = [NSRegularExpression regularExpressionWithPattern:
// #"\\{\\{.*\\}\\}"
// "(.*)?"
// "\\{\\{(//|/.*)\\}\\}"
// options:NSRegularExpressionDotMatchesLineSeparators
// error:&error];
matches = [regex matchesInString:string
options:NSRegularExpressionDotMatchesLineSeparators
range:NSMakeRange(0, [string length])];
for ( NSTextCheckingResult* match in matches )
{
NSLog(#"### %# ###", [string substringWithRange:[match range]]);
}
You can use this pattern
\{\{([^/]*?)\}\}(.*?)\{\{(/\1|//)\}\}
------- ---- --------
| | |->matches closing tag having value same as group 1 or //
| |->content in group 2
|->matches the opening tag value and captures it in group1

Resources