0

Context

I've been going back & forth for a couple of hours trying to solve something and am still not satisfied with the result.

I want to get the username of an iPhone from UIDevice both in English and Spanish. So I've come up with a regex to get ("Andres's iPhone" > "Andres") and ("iPhone de Andres" > "Andres").

The magic is something like:

"(?:iPhone|iphone|phone|iPad|ipad|pad|iPod|ipod|pod)(?:\\s+\\S+)*\\s+de\\s+(.+)|" "(.+)'s\\s+(?:iPhone|iphone|phone|iPad|ipad|pad|iPod|ipod|pod)(?:\\s+\\S+)*"

Problem

When trying to get the substring from [[UIDevice currentDevice] name] the user name can be matched by one of the two alternatives in the regex.

This causes that the actual name might be obtained by:

[[regEx firstMatchInString:str options:0 range:NSMakeRange(0, [str length])] rangeAtIndex:1]

if the first alternative matched; but if the second alternative performs the match, then it is:

[[regEx firstMatchInString:str options:0 range:NSMakeRange(0, [str length])] rangeAtIndex:2]

Notice that, according to the alternative matching, I have to get the first index or the second. For the moment I've worked around this with:

+ (NSString *)getSubstringInString:(NSString *)str matchedByRegEx:(NSRegularExpression *)regEx
{
  NSString * result = nil;

  NSTextCheckingResult * match = [regEx firstMatchInString:str options:0 range:NSMakeRange(0, [str length])];
  for (int i=1; i<[match numberOfRanges]; i++) {
    NSRange matchRange = [match rangeAtIndex:i];
    if (!NSEqualRanges(matchRange, NSMakeRange(NSNotFound, 0))) {
      result = [str substringWithRange:matchRange];
    }
  }

  return result;
}

Actual question

But is there a better way to get the matching substring, disregarding what was the alternative from the regex used ?

Hope I've made myself clear, thanks in advance for any possible help!

1 Answer 1

1

I will get to your question shortly but first some enhancements by using:

options: .CaseInsensitive 

with NSRegularExpression you avoid using expression with and without casing.

So this

(?:iPhone|iphone|phone|iPad|ipad|pad|iPod|ipod|pod)

becomes

(?:iphone|phone|ipad|pad|ipod|pod)

Next by enhancement is i as optional you could still match the other options like:

[i]*(phone|pad|pod)

The expression you need may look like this now:

(?>[i]*(?:phone|pad|pod)\s*de\s)(.+)|(.+)(?='s\s[i]*phone|pad|pod)

The final touch is:

let sample:String = "Andres's iPhone"

let regex = try! NSRegularExpression(pattern: "(?>[i]*(?:phone|pad|pod)\\s*de\\s)(.+)|(.+)(?='s\\s[i]*phone|pad|pod)"
 , options: NSRegularExpressionOptions.CaseInsensitive)

let match = regex.firstMatchInString(sample, options: [], range: NSRange(location: 0, length: sample.characters.count))

print((sample as NSString).substringWithRange(match!.range))
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks for the improvements. I totally overlooked the caps thing: I do set the caseinsensitive option but forgot to update the expression. Good catch!
Regarding the question though, if I do match!.range ([match range] in objc) I get the full range of the string, not the matching expression.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.