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

旧巷老猫 提交于 2019-11-28 21:31:22
Owen Godfrey

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!

Here is an alternative, that gets all names. Also, it does not remove 's' at the end of languages that uses "de" or "'s". Also, it capitalizes the first letter of each name.

Method implementation:

- (NSArray*) newNamesFromDeviceName: (NSString *) deviceName
{
    NSCharacterSet* characterSet = [NSCharacterSet characterSetWithCharactersInString:@" '’\\"];
    NSArray* words = [deviceName componentsSeparatedByCharactersInSet:characterSet];
    NSMutableArray* names = [[NSMutableArray alloc] init];

    bool foundShortWord = false;
    for (NSString *word in words)
    {
        if ([word length] <= 2)
            foundShortWord = true;
        if ([word compare:@"iPhone"] != 0 && [word compare:@"iPod"] != 0 && [word compare:@"iPad"] != 0 && [word length] > 2)
        {
            word = [word stringByReplacingCharactersInRange:NSMakeRange(0,1) withString:[[word substringToIndex:1] uppercaseString]];
            [names addObject:word];
        }
    }
    if (!foundShortWord && [names count] > 1)
    {
        int lastNameIndex = [names count] - 1;
        NSString* name = [names objectAtIndex:lastNameIndex];
        unichar lastChar = [name characterAtIndex:[name length] - 1];
        if (lastChar == 's')
        {
            [names replaceObjectAtIndex:lastNameIndex withObject:[name substringToIndex:[name length] - 1]];
        }
    }
    return names;
}

Usage:

// Add default values for first name and last name
NSString* deviceName = [[UIDevice currentDevice] name];
NSArray* names = [self newNamesFromDeviceName:deviceName];
// This example sets the first and second names as the text property for some text boxes.
[self.txtFirstName setText:[names objectAtIndex:0]];
[self.txtLastName setText:[names objectAtIndex:1]];
[names release];

I've converted original Owen Godfrey answer to Swift and updated the Regexpr to support more patterns like User's iPhone 6S or iPhone 5 de User ...

I've created a Gist here: https://gist.github.com/iGranDav/8a507eb9314391338507

extension UIDevice {

func username() -> String {

    let deviceName = self.name
    let expression = "^(?:iPhone|phone|iPad|iPod)\\s+(?:de\\s+)?(?:[1-9]?S?\\s+)?|(\\S+?)(?:['']?s)?(?:\\s+(?:iPhone|phone|iPad|iPod)\\s+(?:[1-9]?S?\\s+)?)?$|(\\S+?)(?:['']?的)?(?:\\s*(?:iPhone|phone|iPad|iPod))?$|(\\S+)\\s+"

    var username = deviceName

    do {
        let regex = try NSRegularExpression(pattern: expression, options: .CaseInsensitive)
        let matches = regex.matchesInString(deviceName as String,
                                            options: NSMatchingOptions.init(rawValue: 0),
                                            range: NSMakeRange(0, deviceName.characters.count))
        let rangeNotFound = NSMakeRange(NSNotFound, 0)

        var nameParts = [String]()
        for result in matches {
            for i in 1..<result.numberOfRanges {
                if !NSEqualRanges(result.rangeAtIndex(i), rangeNotFound) {
                    nameParts.append((deviceName as NSString).substringWithRange(result.rangeAtIndex(i)).capitalizedString)
                }
            }
        }

        if nameParts.count > 0 {
            username = nameParts.joinWithSeparator(" ")
        }
    }
    catch { NSLog("[Error] While searching for username from device name") }

    return username
}
}

If it's just meant for iPods and iPhones, then why even use a username? If you need to identify the device for your web-service, there are other unique values each device has (such as UDID). Other option would be to let the user pick a contact from the address book that represents themselves and use that data.

NSString *dname=[[UIDevice currentDevice] name];
dname=[dname componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"'的"]][0];
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!