我创建了一个从设备名称中提取用户名的功能。
想法是跳过设置步骤以允许用户在第一次启动应用时直接播放。
这是一种次优方法,因为我永远不会相信设备名称可以保存用户名。问题是:有什么更好的方法可以做到这一点?
我的下面的功能得到了正确的名字......
如果用户将设备名称更改为默认表单以外的其他名称,显然无法使名称正确。
- (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;
}
我用它来建议我的应用中的用户名。这样,大多数用户都不必费心去编写用户名。
我的应用未连接到iTunes或Facebook等任何其他服务,但每个用户都需要一个用户名。那我怎么得到名字?
答案 0 :(得分:8)
我想对Ricky Helegesson的答案进行改进。它具有以下功能;
以下是代码:
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;
}
使用它来返回名称;
NSString* name = [nameFromDeviceName(UIDevice.currentDevice.name) componentsJoinedByString:@" "];
这有点复杂,所以我会解释一下;
如果一个名字以“s”结尾而没有“iPad”之前的撇号,我不会尝试改变它,因为没有万无一失的方法来确定“s”是否是名称的一部分或这个名字的多元化。
享受!
答案 1 :(得分:4)
这是另一种选择,它可以获得所有名称。此外,它不会删除使用“de”或“s”的语言末尾的“s”。此外,它将每个名字的第一个字母大写。
方法实施:
- (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;
}
用法:
// 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];
答案 2 :(得分:3)
我已将原始Owen Godfrey
答案转换为Swift并更新了Regexpr以支持更多模式,例如User's iPhone 6S
或iPhone 5 de User
...
我在这里创建了一个要点: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
}
}
答案 3 :(得分:1)
如果它仅适用于iPod和iPhone,那为什么甚至使用用户名呢?如果需要为Web服务标识设备,则每个设备都有其他唯一值(例如UDID)。其他选择是让用户从代表自己的地址簿中选择一个联系人并使用该数据。
答案 4 :(得分:1)
Swift 5 +本地化
这是一个更新,因为我也想个性化入职流程,并在适用于认知能力下降的应用程序中简化联系人导入过程。随着时间are kept in a Gist的更多详细信息/缺陷/修订。
class Autofiller {
enum NameComponent {
case givenName
case familyName
case fullNameInCurrentPersonNameComponentsFormatterStyle
}
/// Proposes a localized name based on UIDevice.current.name (under the assumption that it contains a name).
/// - Returns: A user's probable first, last, or full name — or a default if detection fails.
///
/// Be aware that:
/// * Non-name words may slip through
/// ```
/// Paul The Great // Paul the Great
/// Paul's Really Old iPhone // Paul
/// ```
/// * This is only tested for romance languages and Chinese.
/// * Chinese names return full name in `givenName` only mode. Options require uncommenting internal code.
///
/// - Parameter name: Choose between given, family, and full name
/// - Parameter style: Options for [PersonNameComponentsFormatter](https://developer.apple.com/documentation/foundation/personnamecomponentsformatter)
/// - Parameter defaultUponFailure: Specify your default string should guessing fail
func guessNameOfDeviceOwner(name: NameComponent,
style: PersonNameComponentsFormatter.Style = .default,
placeholderUponFailure: String = "Good Looking") -> String {
let deviceName = UIDevice.current.name
let nameFormatter = PersonNameComponentsFormatter()
nameFormatter.style = style
if let chineseName = extractNameComponentsInChinese(from: deviceName) {
switch name {
case .givenName:
return nameFormatter.string(from: chineseName)
// DEFAULT: RETURN FULL NAME (EVEN WHEN OTHER LANGUAGES RETURN GIVEN ONLY)
// OPTION: CUTESY INFORMAL GIVEN NAME
// if let givenName = chineseName.givenName {
// return String("小").appending(givenName)
case .familyName:
if let familyName = chineseName.familyName {
return familyName
}
// OPTION: RESPECTFUL FAMILY NAME
// if let familyName = chineseName.familyName {
// return String("老").appending(familyName)
case .fullNameInCurrentPersonNameComponentsFormatterStyle:
return nameFormatter.string(from: chineseName)
}
}
if let latinName = extractNameComponentsByPrefixOrSuffix(from: deviceName) {
switch name {
case .givenName:
if let givenName = latinName.givenName {
return givenName
}
case .familyName:
if let familyName = latinName.familyName {
return familyName
}
case .fullNameInCurrentPersonNameComponentsFormatterStyle:
return nameFormatter.string(from: latinName)
}
}
return placeholderUponFailure
}
/// Process common styles for English (Ryan's iPhone), Swedish (Ryan iPhone), French (iPhone de Ryan)
private func extractNameComponentsByPrefixOrSuffix(from input: String) -> PersonNameComponents? {
let formatter = PersonNameComponentsFormatter()
let prefixes = ["iPhone de ",
"iPad de ",
"iPod de "
]
for prefix in prefixes {
guard input.contains(prefix) else { continue }
var inputComponents = input.components(separatedBy: prefix)
// First element is either empty or assumed to be extraneous
inputComponents.removeFirst()
let possibleName = inputComponents.joined()
// Note: .personNameComponents(from:) will ignore brackets, parentheses
guard let nameComponents = formatter.personNameComponents(from: possibleName) else { return nil }
return nameComponents
}
let suffixes = ["'s iPhone",
"'s iPad'",
"'s iPod",
"'s ", // Capture if user removed "i" or has a descriptor (e.g., Paul's Really Old iPhone)
"iPhone", // For Swedish style, reached if posessive language not present
"iPad",
"iPod",
"Phone", // Latter iterations, if reached, cover an edge case like me, a nerd who named his phone "RyPhone"
"Pad",
"Pod"
]
for suffix in suffixes {
guard input.contains(suffix) else { continue }
var inputComponents = input.components(separatedBy: suffix)
// The last component is either emptty, contains the model (e.g., "XS"), or duplicate device number (e.g., "(2)")
inputComponents.removeLast()
let possibleName = inputComponents.joined()
guard let nameComponents = formatter.personNameComponents(from: possibleName) else { return nil }
return nameComponents
}
// If no prefix/suffix matches, attempt to parse a name. Otherwise return nil to indicate failure.
guard let possibleName = formatter.personNameComponents(from: input) else { return nil }
return possibleName
}
/// Process for Chinese name apart from neighboring English (e.g., "某人的iPhone")
private func extractNameComponentsInChinese(from input: String) -> PersonNameComponents? {
guard let range = input.range(of: "\\p{Han}*\\p{Han}", options: .regularExpression) else { return nil }
// Extract of only Chinese characters, ignoring "iPhone" etc
var possibleName = input[range]
// Remove possible instance of "cell phone"
possibleName = Substring(String(possibleName).replacingOccurrences(of: "手机", with: ""))
// Remove possible posessive referring to iPhone or cell phone
if possibleName.last == "的" { possibleName.removeLast(1) }
let formatter = PersonNameComponentsFormatter()
guard let nameComponents = formatter.personNameComponents(from: String(possibleName)) else { return nil }
return nameComponents
}
}
答案 5 :(得分:0)
NSString *dname=[[UIDevice currentDevice] name];
dname=[dname componentsSeparatedByCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"'的"]][0];