Repository: lexrus/PhoneticContacts Branch: master Commit: df88007fc3b3 Files: 6 Total size: 15.5 KB Directory structure: gitextract_dipsd01w/ ├── .gitignore ├── PhoneticContacts.xcodeproj/ │ ├── project.pbxproj │ └── project.xcworkspace/ │ ├── contents.xcworkspacedata │ └── xcshareddata/ │ └── WorkspaceSettings.xcsettings ├── README.md └── main.swift ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Created by https://www.gitignore.io/api/swift,appcode,xcode,osx ### Swift ### # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Build generated build/ DerivedData ## Various settings *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata ## Other *.xccheckout *.moved-aside *.xcuserstate *.xcscmblueprint ## Obj-C/Swift specific *.hmap *.ipa ## Playgrounds timeline.xctimeline playground.xcworkspace # Swift Package Manager # # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. # Packages/ .build/ # CocoaPods # # We recommend against adding the Pods directory to your .gitignore. However # you should judge for yourself, the pros and cons are mentioned at: # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control # # Pods/ # Carthage # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts Carthage/Build # fastlane # # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the # screenshots whenever they are needed. # For more information about the recommended setup visit: # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md fastlane/report.xml fastlane/screenshots ### AppCode ### # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm *.iml ## Directory-based project format: .idea/ # if you remove the above rule, at least ignore the following: # User-specific stuff: # .idea/workspace.xml # .idea/tasks.xml # .idea/dictionaries # .idea/shelf # Sensitive or high-churn files: # .idea/dataSources.ids # .idea/dataSources.xml # .idea/sqlDataSources.xml # .idea/dynamic.xml # .idea/uiDesigner.xml # Gradle: # .idea/gradle.xml # .idea/libraries # Mongo Explorer plugin: # .idea/mongoSettings.xml ## File-based project format: *.ipr *.iws ## Plugin-specific files: # IntelliJ /out/ # mpeltonen/sbt-idea plugin .idea_modules/ # JIRA plugin atlassian-ide-plugin.xml # Crashlytics plugin (for Android Studio and IntelliJ) com_crashlytics_export_strings.xml crashlytics.properties crashlytics-build.properties fabric.properties ### Xcode ### # Xcode # # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore ## Build generated build/ DerivedData ## Various settings *.pbxuser !default.pbxuser *.mode1v3 !default.mode1v3 *.mode2v3 !default.mode2v3 *.perspectivev3 !default.perspectivev3 xcuserdata ## Other *.xccheckout *.moved-aside *.xcuserstate ### OSX ### .DS_Store .AppleDouble .LSOverride # Icon must end with two \r Icon # Thumbnails ._* # Files that might appear in the root of a volume .DocumentRevisions-V100 .fseventsd .Spotlight-V100 .TemporaryItems .Trashes .VolumeIcon.icns # Directories potentially created on remote AFP share .AppleDB .AppleDesktop Network Trash Folder Temporary Items .apdisk ================================================ FILE: PhoneticContacts.xcodeproj/project.pbxproj ================================================ // !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; objects = { /* Begin PBXBuildFile section */ D744DD001C6738BD00D01E04 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = D744DCFF1C6738BD00D01E04 /* main.swift */; }; /* End PBXBuildFile section */ /* Begin PBXCopyFilesBuildPhase section */ D7E7F1C71661184E008C3C32 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = /usr/share/man/man1/; dstSubfolderSpec = 0; files = ( ); runOnlyForDeploymentPostprocessing = 1; }; /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ D744DCFF1C6738BD00D01E04 /* main.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; D7E7F1C91661184E008C3C32 /* PhoneticContacts */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = PhoneticContacts; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ D7E7F1C61661184E008C3C32 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ D7E7F1BE1661184E008C3C32 = { isa = PBXGroup; children = ( D744DCFF1C6738BD00D01E04 /* main.swift */, D7E7F1CA1661184E008C3C32 /* Products */, ); sourceTree = ""; }; D7E7F1CA1661184E008C3C32 /* Products */ = { isa = PBXGroup; children = ( D7E7F1C91661184E008C3C32 /* PhoneticContacts */, ); name = Products; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ D7E7F1C81661184E008C3C32 /* PhoneticContacts */ = { isa = PBXNativeTarget; buildConfigurationList = D7E7F1D81661184E008C3C32 /* Build configuration list for PBXNativeTarget "PhoneticContacts" */; buildPhases = ( D7E7F1C51661184E008C3C32 /* Sources */, D7E7F1C61661184E008C3C32 /* Frameworks */, D7E7F1C71661184E008C3C32 /* CopyFiles */, ); buildRules = ( ); dependencies = ( ); name = PhoneticContacts; productName = PhoneticContacts; productReference = D7E7F1C91661184E008C3C32 /* PhoneticContacts */; productType = "com.apple.product-type.tool"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ D7E7F1C01661184E008C3C32 /* Project object */ = { isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0720; LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Lex Tang"; TargetAttributes = { D7E7F1C81661184E008C3C32 = { LastSwiftMigration = 0900; }; }; }; buildConfigurationList = D7E7F1C31661184E008C3C32 /* Build configuration list for PBXProject "PhoneticContacts" */; compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( en, ); mainGroup = D7E7F1BE1661184E008C3C32; productRefGroup = D7E7F1CA1661184E008C3C32 /* Products */; projectDirPath = ""; projectRoot = ""; targets = ( D7E7F1C81661184E008C3C32 /* PhoneticContacts */, ); }; /* End PBXProject section */ /* Begin PBXSourcesBuildPhase section */ D7E7F1C51661184E008C3C32 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( D744DD001C6738BD00D01E04 /* main.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin XCBuildConfiguration section */ D7E7F1D61661184E008C3C32 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; ONLY_ACTIVE_ARCH = YES; SDKROOT = macosx; }; name = Debug; }; D7E7F1D71661184E008C3C32 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_OBJC_ARC = YES; CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; CLANG_WARN_STRICT_PROTOTYPES = YES; CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNDECLARED_SELECTOR = YES; GCC_WARN_UNINITIALIZED_AUTOS = YES; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; MACOSX_DEPLOYMENT_TARGET = 10.10; SDKROOT = macosx; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; }; name = Release; }; D7E7F1D91661184E008C3C32 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; }; name = Debug; }; D7E7F1DA1661184E008C3C32 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { CLANG_ENABLE_MODULES = YES; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_SWIFT3_OBJC_INFERENCE = On; SWIFT_VERSION = 4.0; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ D7E7F1C31661184E008C3C32 /* Build configuration list for PBXProject "PhoneticContacts" */ = { isa = XCConfigurationList; buildConfigurations = ( D7E7F1D61661184E008C3C32 /* Debug */, D7E7F1D71661184E008C3C32 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; D7E7F1D81661184E008C3C32 /* Build configuration list for PBXNativeTarget "PhoneticContacts" */ = { isa = XCConfigurationList; buildConfigurations = ( D7E7F1D91661184E008C3C32 /* Debug */, D7E7F1DA1661184E008C3C32 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = D7E7F1C01661184E008C3C32 /* Project object */; } ================================================ FILE: PhoneticContacts.xcodeproj/project.xcworkspace/contents.xcworkspacedata ================================================ ================================================ FILE: PhoneticContacts.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings ================================================ BuildSystemType Latest ================================================ FILE: README.md ================================================ # PhoneticContacts ![Language](https://img.shields.io/badge/Language-Swift%204-orange.svg) [![Git](https://img.shields.io/badge/GitHub-lexrus-blue.svg?style=flat)](https://github.com/lexrus) [![Twitter](https://img.shields.io/badge/Twitter-@lexrus-blue.svg?style=flat)](http://twitter.com/lexrus) 为你的联系人加上拼音属性, 这样即使你的 iPhone 设置成英文, 也能有__按姓氏拼音首字母分段__的功能。 这个工具参考了 [V2EX 网友写的 AppleScript](http://v2ex.com/t/52860), 但使用 CFStringTransform 查拼音,速度更快。 另外,有些汉字姓氏的读音比较特殊 (如「曾」作为姓时读作 zeng)。 我在网上随便找了一些,做了替换的处理,可能不全,欢迎补充。 请在 Xcode 9 里打开此项目,command + r 运行后联系人就有拼音属性了。 过不了多久(看脸),这些更新后的联系人会通过 iCloud 同步到 iPhone。 ================================================ FILE: main.swift ================================================ // // main.swift // PhoneticContacts // // Created by Lex on 2/7/16. // Copyright © 2016 Lex Tang. All rights reserved. // import Foundation import AddressBook extension String { func upcaseInitial() -> String { guard let firstChar = first else { return "" } return String(firstChar).uppercased() + dropFirst() } func phonetic() -> String { let src = NSMutableString(string: self) as CFMutableString CFStringTransform(src, nil, kCFStringTransformMandarinLatin, false) // Transform NínHǎo to NinHao CFStringTransform(src, nil, kCFStringTransformStripCombiningMarks, false) let s = src as String if s != self { return s .components(separatedBy: " ") .map { $0.upcaseInitial() } .reduce("", +) } return self } func phoneticLast() -> String { let SpecialLastName: [String: String] = [ "柏": "bai", "鲍": "bao", "贲": "ben", "秘": "bi", "薄": "bo", "卜": "bu", "岑": "cen", "晁": "chao", "谌": "chen", "种": "chong", "褚": "chu", "啜": "chuai", "单": "chan", "郗": "chi", "邸": "di", "都": "du", "缪": "miao", "宓": "mi", "费": "fei", "苻": "fu", "睢": "sui", "区": "ou", "华": "hua", "庞": "pang", "查": "zha", "佘": "she", "仇": "qiu", "靳": "jin", "解": "xie", "繁": "po", "折": "she", "员": "yun", "祭": "zhai", "芮": "rui", "覃": "tan", "牟": "mou", "蕃": "pi", "戚": "qi", "瞿": "qu", "冼": "xian", "洗": "xian", "郤": "xi", "庹": "tuo", "彤": "tong", "佟": "tong", "妫": "gui", "句": "gou", "郝": "hao", "曾": "zeng", "乐": "yue", "蔺": "lin", "隽": "juan", "臧": "zang", "庾": "yu", "詹": "zhan", "禚": "zhuo", "迮": "ze", "沈": "shen", "沉": "shen", "尉迟": "yuchi", "长孙": "zhangsun", "中行": "zhonghang", "万俟": "moqi", "单于": "chanyu" ] if let specialLastName = SpecialLastName[self] { return specialLastName.upcaseInitial() } return self } } let ab = ABAddressBook() ab.people().forEach { guard let people = $0 as? ABPerson else { return } if let lastName = people.value(forProperty: kABLastNameProperty) as? String { _ = try? people.setValue( lastName.phoneticLast().phonetic(), forProperty: kABLastNamePhoneticProperty, error: () ) print(lastName, lastName.phoneticLast().phonetic(), separator: "->", terminator: ", ") } if let firstName = people.value(forProperty: kABFirstNameProperty) as? String { _ = try? people.setValue( firstName.phonetic(), forProperty: kABFirstNamePhoneticProperty, error: () ) print(firstName, firstName.phonetic(), separator: "->", terminator: " | ") } } ab.save()