Skip to content

Commit

Permalink
Merge pull request #7 from marmelroy/feature_asyoutypeformatter
Browse files Browse the repository at this point in the history
Better formatter
  • Loading branch information
marmelroy committed Nov 6, 2015
2 parents 850ff1a + 9cddfd4 commit f078e9d
Show file tree
Hide file tree
Showing 10 changed files with 400 additions and 13,512 deletions.
4 changes: 4 additions & 0 deletions PhoneNumberKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
3420CF5E1BE8959F00FAE34F /* Formatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3420CF5D1BE8959F00FAE34F /* Formatter.swift */; };
3422D9BA1BE6A2D500867D02 /* ParseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3422D9B91BE6A2D500867D02 /* ParseManager.swift */; };
342418681BB6E5A000EE70E7 /* PhoneNumberKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 342418671BB6E5A000EE70E7 /* PhoneNumberKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
3424186F1BB6E5A000EE70E7 /* PhoneNumberKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 342418641BB6E5A000EE70E7 /* PhoneNumberKit.framework */; };
Expand Down Expand Up @@ -37,6 +38,7 @@
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
3420CF5D1BE8959F00FAE34F /* Formatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Formatter.swift; sourceTree = "<group>"; };
3422D9B91BE6A2D500867D02 /* ParseManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParseManager.swift; sourceTree = "<group>"; };
342418641BB6E5A000EE70E7 /* PhoneNumberKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = PhoneNumberKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
342418671BB6E5A000EE70E7 /* PhoneNumberKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PhoneNumberKit.h; sourceTree = "<group>"; };
Expand Down Expand Up @@ -112,6 +114,7 @@
342418671BB6E5A000EE70E7 /* PhoneNumberKit.h */,
342418691BB6E5A000EE70E7 /* Info.plist */,
346922681BC023A60023482F /* PhoneNumberKit.swift */,
3420CF5D1BE8959F00FAE34F /* Formatter.swift */,
3424187F1BB705B500EE70E7 /* PhoneNumber.swift */,
346922661BC01DCC0023482F /* Metadata.swift */,
342548EF1BE7EED500FBE524 /* MetadataTypes.swift */,
Expand Down Expand Up @@ -256,6 +259,7 @@
files = (
342418821BB70F5200EE70E7 /* PhoneNumberParser.swift in Sources */,
346922671BC01DCC0023482F /* Metadata.swift in Sources */,
3420CF5E1BE8959F00FAE34F /* Formatter.swift in Sources */,
346922691BC023A60023482F /* PhoneNumberKit.swift in Sources */,
3422D9BA1BE6A2D500867D02 /* ParseManager.swift in Sources */,
34566C9A1BC112C500715E6B /* RegularExpressions.swift in Sources */,
Expand Down
40 changes: 36 additions & 4 deletions PhoneNumberKit/Constants.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ import Foundation

// MARK: Private Enums

enum PNNumberFormat {
case E164
case International
case National
}

enum PNCountryCodeSource {
case NumberWithPlusSign
case NumberWithIDD
Expand All @@ -31,6 +37,14 @@ enum PNValidationResult: ErrorType {

// MARK: Public Enums

/**
Enumeration for parsing error types
- TechnicalError: A generic error occured.
- NotANumber: The string provided is not a number
- TooLong: The string provided is too long to be a valid number
- TooShort: The string provided is too short to be a valid number
- InvalidCountryCode: A country code could not be found or the one found was invalid
*/
public enum PNParsingError: ErrorType {
case TechnicalError
case NotANumber
Expand All @@ -39,17 +53,31 @@ public enum PNParsingError: ErrorType {
case InvalidCountryCode
}

/**
Phone number type enumeration
- FixedLine: Fixed line numbers
- Mobile: Mobile numbers
- Pager: Pager numbers
- PersonalNumber: Personal number numbers
- PremiumRate: Premium rate numbers
- SharedCost: Shared cost numbers
- TollFree: Toll free numbers
- Voicemail: Voice mail numbers
- VOIP: Voip numbers
- UAN: UAN numbers
- Unknown: Unknown number type
*/
public enum PNPhoneNumberType {
case FixedLine
case Mobile
case TollFree
case Pager
case PersonalNumber
case PremiumRate
case SharedCost
case TollFree
case Voicemail
case VOIP
case PersonalNumber
case Pager
case UAN
case Voicemail
case Unknown
}

Expand All @@ -62,6 +90,10 @@ let PNMaxLengthForNSN: Int = 16
let PNNonBreakingSpace: String = "\u{00a0}"
let PNPlusChars: String = "++"
let PNValidDigitsString: String = "0-90-9٠-٩۰-۹"
let PNDefaultExtnPrefix: String = " ext. "
let PNFirstGroupPattern: String = "(\\$\\d)"
let PNNPPattern: String = "\\$NP"
let PNFGPattern: String = "\\$FG"

// MARK: Patterns

Expand Down
155 changes: 155 additions & 0 deletions PhoneNumberKit/Formatter.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
//
// Formatter.swift
// PhoneNumberKit
//
// Created by Roy Marmelstein on 03/11/2015.
// Copyright © 2015 Roy Marmelstein. All rights reserved.
//

import Foundation

class Formatter {

// MARK: Formatting functions
let regex = RegularExpressions.sharedInstance

/**
Formats phone numbers for display
- Parameter phoneNumber: Phone number object.
- Returns: Modified national number ready for display.
*/
func formatPhoneNumber(phoneNumber: PhoneNumber, formatType: PNNumberFormat) -> String {
let metadata = Metadata.sharedInstance
var formattedNationalNumber = phoneNumber.adjustedNationalNumber()
if let regionMetadata = metadata.metadataPerCode[phoneNumber.countryCode] {
formattedNationalNumber = formatNationalNumber(formattedNationalNumber, regionMetadata: regionMetadata, formatType: formatType)
if let formattedExtension = formatExtension(phoneNumber.numberExtension, regionMetadata: regionMetadata) {
formattedNationalNumber = formattedNationalNumber + formattedExtension
}
}
return formattedNationalNumber
}


/**
Formats extension for display
- Parameter numberExtension: Number extension string.
- Returns: Modified number extension with either a preferred extension prefix or the default one.
*/
func formatExtension(numberExtension: String?, regionMetadata: MetadataTerritory) -> String? {
if let extns = numberExtension {
if let preferredExtnPrefix = regionMetadata.preferredExtnPrefix {
return "\(preferredExtnPrefix)\(extns)"
}
else {
return "\(PNDefaultExtnPrefix)\(extns)"
}
}
return nil
}

/**
Formats national number for display
- Parameter nationalNumber: National number string.
- Returns: Modified nationalNumber for display.
*/
func formatNationalNumber(nationalNumber: String, regionMetadata: MetadataTerritory, formatType: PNNumberFormat) -> String {
let formats = regionMetadata.numberFormats
var selectedFormat : MetadataPhoneNumberFormat?
for format in formats {
if let leadingDigitPattern = format.leadingDigitsPatterns?.last {
if (regex.stringPositionByRegex(leadingDigitPattern, string: String(nationalNumber)) == 0) {
if (regex.matchesEntirely(format.pattern, string: String(nationalNumber))) {
selectedFormat = format
break;
}
}
}
else {
if (regex.matchesEntirely(format.pattern, string: String(nationalNumber))) {
selectedFormat = format
break;
}
}
}
if let formatPattern = selectedFormat {
let numberFormatRule = (formatType == PNNumberFormat.International && formatPattern.intlFormat != nil) ? formatPattern.intlFormat : formatPattern.format
var formattedNationalNumber : String?
var prefixFormattingRule = formatPattern.nationalPrefixFormattingRule
if prefixFormattingRule?.characters.count > 0 {
let nationalPrefix = regionMetadata.nationalPrefix
if nationalPrefix?.characters.count > 0 {
prefixFormattingRule = regex.replaceStringByRegex(PNNPPattern, string: prefixFormattingRule!, template: nationalPrefix!)
prefixFormattingRule = regex.replaceStringByRegex(PNFGPattern, string: prefixFormattingRule!, template:"\\$1")
}
else {
prefixFormattingRule = ""
}
}
if (formatType == PNNumberFormat.National && regex.hasValue(prefixFormattingRule)){
let replacePattern = regex.replaceFirstStringByRegex(PNFirstGroupPattern, string: numberFormatRule!, templateString: prefixFormattingRule!)
formattedNationalNumber = self.regex.replaceStringByRegex(formatPattern.pattern!, string: nationalNumber, template: replacePattern)
}
else {
formattedNationalNumber = self.regex.replaceStringByRegex(formatPattern.pattern!, string: nationalNumber, template: numberFormatRule!)
}
return formattedNationalNumber!
}
else {
return nationalNumber
}
}

}

public extension PhoneNumber {

// MARK: Formatting extenstions to PhoneNumber

/**
Formats a phone number to E164 format (e.g. +33689123456)
- Returns: A string representing the phone number in E164 format.
*/
public func toE164() -> String {
let formattedNumber: String = "+" + String(countryCode) + adjustedNationalNumber()
return formattedNumber
}

/**
Formats a phone number to International format (e.g. +33 6 89 12 34 56)
- Returns: A string representing the phone number in International format.
*/
public func toInternational() -> String {
let formatter = Formatter()
let formattedNationalNumber = formatter.formatPhoneNumber(self, formatType: .International)
let formattedNumber: String = "+" + String(countryCode) + " " + formattedNationalNumber
return formattedNumber
}

/**
Formats a phone number to local national format (e.g. 06 89 12 34 56)
- Returns: A string representing the phone number in the local national format.
*/
public func toNational() -> String {
let formatter = Formatter()
let formattedNationalNumber = formatter.formatPhoneNumber(self, formatType: .National)
let formattedNumber: String = formattedNationalNumber
return formattedNumber
}

/**
Adjust national number for display by adding leading zero if needed. Used for basic formatting functions.
- Returns: A string representing the adjusted national number.
*/
private func adjustedNationalNumber() -> String {
if (self.leadingZero == true) {
return "0" + String(nationalNumber)
}
else {
return String(nationalNumber)
}
}

}


Loading

0 comments on commit f078e9d

Please sign in to comment.