Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Better way to get the user's name from device?

Tags:

ios

I made a function that extracts a user name from the device name.

The idea is to skip setup steps to allow the user to go straight to play upon starting the app the first time.

This is a sub-optimal approach, as I can never trust the device name to hold the name of the user. The question is: What is a better way to do this?

My function below gets the right name ...

  • ... if the default name of the device has not changed ("Sanna's iPod")
  • ... in English,
  • ... in French and similar ("iPod de Sanna")
  • ... in Swedish and similar ("Sannas iPod") if the name does not end with S ("Johannes iPod" => returns "Johanne" but should rather return "Johannes" to be correct, as the name itself ends with an S.)

It obviously does not get the name right if the user has changed the name of the device to something else than the default form.

- (NSString *) extractPlayerNameFromDeviceName: (NSString *) deviceName  {

    // get words in device name
    NSArray *words = [deviceName componentsSeparatedByString:@" "];
    NSMutableArray *substrings = [[NSMutableArray alloc] init]; 
    for (NSString *word in words) {
        NSArray *subwords = [word componentsSeparatedByString:@"'"];
        [substrings addObjectsFromArray:subwords];
    }

    // find the name part of the device name
    NSString *playerName = [NSString stringWithString: @""];
    for (NSString *word in substrings) {
        if ([word compare:@"iPhone"] != 0
            && [word compare:@"iPod"] != 0
            && [word compare:@"iPad"] != 0
            && [word length] > 2) {
            playerName = word;
        }
    }

    // remove genitive
    unichar lastChar = [playerName characterAtIndex:[playerName length] - 1];
    if (lastChar == 's') {
        playerName = [playerName substringToIndex:[playerName length] - 1];
    }
    lastChar = [playerName characterAtIndex:[playerName length] - 1];
    if (lastChar == '\'') {
        playerName = [playerName substringToIndex:[playerName length] - 1];
    }
    return playerName;
}

I use it for suggesting a username in my app. This way, most users won't have to bother writing their usernames.

My app is not connected to any other service like iTunes or Facebook, but every user needs a user name. So how do I get the name?

like image 459
JOG Avatar asked Nov 24 '11 20:11

JOG


Video Answer


1 Answers

I'd like to offer an improvement on Ricky Helegesson's answer. It has the following features;

  • It is a little smaller, although less efficient because it uses regular expressions, but then I suppose it should be called only once.
  • I have expended it to include "phone" as well as "iPod, "iPhone" and "iPad".
  • It only removes "'s" when it immediately preceded by "iPad", "iPhone" etc., but only at the end of the string.
  • It removes "iPad" and so on when they are the first word, as in "iPad Simulator".
  • It capitalises the first letter of each word.
  • It is case insensitive.
  • It is a function because it has no dependencies.

Here is the code:

NSArray * nameFromDeviceName(NSString * deviceName)
{
    NSError * error;
    static NSString * expression = (@"^(?:iPhone|phone|iPad|iPod)\\s+(?:de\\s+)?|"
                                    "(\\S+?)(?:['’]?s)?(?:\\s+(?:iPhone|phone|iPad|iPod))?$|"
                                    "(\\S+?)(?:['’]?的)?(?:\\s*(?:iPhone|phone|iPad|iPod))?$|"
                                    "(\\S+)\\s+");
    static NSRange RangeNotFound = (NSRange){.location=NSNotFound, .length=0};
    NSRegularExpression * regex = [NSRegularExpression regularExpressionWithPattern:expression
                                                                            options:(NSRegularExpressionCaseInsensitive)
                                                                              error:&error];
    NSMutableArray * name = [NSMutableArray new];
    for (NSTextCheckingResult * result in [regex matchesInString:deviceName
                                                         options:0
                                                           range:NSMakeRange(0, deviceName.length)]) {
        for (int i = 1; i < result.numberOfRanges; i++) {
            if (! NSEqualRanges([result rangeAtIndex:i], RangeNotFound)) {
                [name addObject:[deviceName substringWithRange:[result rangeAtIndex:i]].capitalizedString];
            }
        }
    }
    return name;
}

To use this for return a name;

NSString* name = [nameFromDeviceName(UIDevice.currentDevice.name) componentsJoinedByString:@" "];

This is somewhat complex, so I'll explain;

  1. The regular expression holds three parts;
    1. At the start of the string, match but do not return "iPhone", "iPod", "iPad" or "phone" and an optional word "de".
    2. At the end of the string, match and return a word that is followed by and optional " 's" (which is not returned) and then "iPad", "iPhone", "iPod" or "phone" (which are not returned either).
    3. This match is the same as the previous, but it should work for Chinese device names. (Adapted from Travis Worm's submission. Please tell me if its wrong.)
    4. Match and return any word that doesn't match the previous rules.
  2. Iterate through all the matches, capitalise them and add them to the array.
  3. Return the array.

If a name ends in "s" without an apostrophe before "iPad" etc., I don't try to change it because there is not foolproof way of figuring out if the "s" is a part of the name or a pluralisation of the name.

Enjoy!

like image 96
Owen Godfrey Avatar answered Oct 19 '22 15:10

Owen Godfrey