I just implemented SFSpeechRecognizer, because I want it to dictate some numbers, but the issue that I'm encountering is that if I say "one" the result.bestTranscription.formattedString is "one", but if I say "ten" the result throws "10", how can I manage to get single digit numbers to be represented by the actual number not the symphonic "one".
You can use NumberFormatter setting numberStyle to .spellOut and use its number(from: String) to convert your string to number. If you need a string from that number just initialise a new string from it. Make sure if you only want to detect English words (not locale sensitive) to set the formatter locale to "en_US_POSIX"
let string = "one"
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "en_US_POSIX") // if you dont set locale it will use current locale so it wont detect one if the language it is not english at the devices locale
numberFormatter.numberStyle = .spellOut
numberFormatter.number(from: string) // 1
Testing another language/locale
let string = "um"
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "pt_BR")
numberFormatter.numberStyle = .spellOut
numberFormatter.number(from: string) // 1
Related
I am fairly new to Swift and having a great deal of trouble finding a way to add a space as a thousand separator.
What I am hoping to achieve is taking the result of a calculation and displaying it in a textfield so that the format is:
2 358 000
instead of
2358000
for example.
I am not sure if I should be formatting the Int value and then converting it to a String, or adding the space after the Int value is converted to a String. Any help would be greatly appreciated.
You can use NSNumberFormatter to specify a different grouping separator as follow:
update: Xcode 11.5 • Swift 5.2
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.groupingSeparator = " "
return formatter
}()
}
extension Numeric {
var formattedWithSeparator: String { Formatter.withSeparator.string(for: self) ?? "" }
}
2358000.formattedWithSeparator // "2 358 000"
2358000.99.formattedWithSeparator // "2 358 000.99"
let int = 2358000
let intFormatted = int.formattedWithSeparator // "2 358 000"
let decimal: Decimal = 2358000
let decimalFormatted = decimal.formattedWithSeparator // "2 358 000"
let decimalWithFractionalDigits: Decimal = 2358000.99
let decimalWithFractionalDigitsFormatted = decimalWithFractionalDigits.formattedWithSeparator // "2 358 000.99"
If you need to display your value as currency with current locale or with a fixed locale:
extension Formatter {
static let number = NumberFormatter()
}
extension Locale {
static let englishUS: Locale = .init(identifier: "en_US")
static let frenchFR: Locale = .init(identifier: "fr_FR")
static let portugueseBR: Locale = .init(identifier: "pt_BR")
// ... and so on
}
extension Numeric {
func formatted(with groupingSeparator: String? = nil, style: NumberFormatter.Style, locale: Locale = .current) -> String {
Formatter.number.locale = locale
Formatter.number.numberStyle = style
if let groupingSeparator = groupingSeparator {
Formatter.number.groupingSeparator = groupingSeparator
}
return Formatter.number.string(for: self) ?? ""
}
// Localized
var currency: String { formatted(style: .currency) }
// Fixed locales
var currencyUS: String { formatted(style: .currency, locale: .englishUS) }
var currencyFR: String { formatted(style: .currency, locale: .frenchFR) }
var currencyBR: String { formatted(style: .currency, locale: .portugueseBR) }
// ... and so on
var calculator: String { formatted(groupingSeparator: " ", style: .decimal) }
}
Usage:
1234.99.currency // "$1,234.99"
1234.99.currencyUS // "$1,234.99"
1234.99.currencyFR // "1 234,99 €"
1234.99.currencyBR // "R$ 1.234,99"
1234.99.calculator // "1 234.99"
Note: If you would like to have a space with the same width of a period you can use "\u{2008}"
unicode spaces
formatter.groupingSeparator = "\u{2008}"
You want to use NSNumberFormatter:
let fmt = NSNumberFormatter()
fmt.numberStyle = .DecimalStyle
fmt.stringFromNumber(2358000) // with my locale, "2,358,000"
fmt.locale = NSLocale(localeIdentifier: "fr_FR")
fmt.stringFromNumber(2358000) // "2 358 000"
With Swift 5, when you need to format the display of numbers, NumberFormatter is the right tool.
NumberFormatter has a property called numberStyle. numberStyle can be set to a value of NumberFormatter.Style.decimal in order to set the formatter's style to decimal.
Therefore, in the simplest case when you want to format a number with decimal style, you can use the following Playground code:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = NumberFormatter.Style.decimal
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
According to the user's current locale, this code will print Optional("2,358,000") for en_US or Optional("2 358 000") for fr_FR.
Note that the following code snippet that uses the NumberFormatter's locale property set to Locale.current is equivalent to the previous Playground code:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale.current
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
The Playground code below that uses the NumberFormatter's groupingSeparator property set to Locale.current.groupingSeparator is also equivalent to the former:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.groupingSeparator = Locale.current.groupingSeparator
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
Otherwise, if you want to set the number formatting with a specific locale formatting style, you may use the following Playground code:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "fr_FR")
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
// prints: Optional("2 358 000")
However, if what you really want is to enforce a specific grouping separator, you may use the Playground code below:
import Foundation
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.groupingSeparator = " "
let amount = 2358000
let formattedString = formatter.string(for: amount)
print(String(describing: formattedString))
// prints: Optional("2 358 000")
Leo Dabus's answer translated to Swift 3:
Into any .swift file, out of a class:
struct Number {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.groupingSeparator = " " // or possibly "." / ","
formatter.numberStyle = .decimal
return formatter
}()
}
extension Integer {
var stringWithSepator: String {
return Number.withSeparator.string(from: NSNumber(value: hashValue)) ?? ""
}
}
Usage:
let myInteger = 2358000
let myString = myInteger.stringWithSeparator // "2 358 000"
Code:
//5000000
let formatter = NumberFormatter()
formatter.groupingSeparator = " "
formatter.locale = Locale(identifier: "en_US")
formatter.numberStyle = .decimal.
Output:
5 000 000
I was looking for a currency format like $100,000.00
I accomplished it customizing the implementation Leo Dabus like this
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencyGroupingSeparator = ","
formatter.locale = Locale(identifier: "en_US") //for USA's currency patter
return formatter
}()
}
extension Numeric {
var formattedWithSeparator: String {
return Formatter.withSeparator.string(for: self) ?? ""
}
}
Try this
func addPoints(inputNumber: NSMutableString){
var count: Int = inputNumber.length
while count >= 4 {
count = count - 3
inputNumber.insert(" ", at: count) // you also can use ","
}
print(inputNumber)
}
The call:
addPoints(inputNumber: "123456")
The result:
123 456 (or 123,456)
In iOS 13 it appears that in certain Locales, NumberFormatter appends a Unicode NO-BREAK SPACE or NARROW NO-BREAK SPACE to a string representation of the number, even when NumberFormatter's currencySymbol property is set to "" (blank).
Here's an example of this:
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .currency
numberFormatter.currencySymbol = ""
numberFormatter.locale = Locale(identifier: "uk_US (current)")
let numberString = numberFormatter.string(from: NSNumber(value: 1))!
print ("-->\(numberString)<--")
Does anyone know a way of suppressing that appended space, short of having to filter it out of every converted string in other code?
You can set your own positive and negative formats to avoid such cases. Note that you should always set the locale before setting the formats and there is no need to initialize a NSNumber object from your value, you can use Formatter's string(for:) method:
let numberFormatter = NumberFormatter()
numberFormatter.locale = Locale(identifier: "uk_US")
numberFormatter.numberStyle = .currency
numberFormatter.positiveFormat = "##0.00"
numberFormatter.negativeFormat = "-##0.00"
let value: Double = 1
let numberString = numberFormatter.string(for: value) ?? "" // "1,00"
print ("-->\(numberString)<--") // "-->1,00<--\n"
For locales where there might not have fraction digits:
let numberFormatter = NumberFormatter()
// numberFormatter.locale = Locale(identifier: "ja_JP")
numberFormatter.numberStyle = .currency
let digits = numberFormatter.minimumFractionDigits
let zeros = digits == 0 ? "" : "." + String(repeating: "0", count: digits)
numberFormatter.positiveFormat = "##0" + zeros
numberFormatter.negativeFormat = "-##0" + zeros
let value: Double = 1
let numberString = numberFormatter.string(for: value) ?? "" // "1"
print ("-->\(numberString)<--") // "-->1<--\n"
how to set NumberFormatter to return currency symbol not the iso one but local which is visible in iOS locale settings pane. Like for Polish currency I need to have “zł” symbol not the “PLN”.
I cannot find any way to get it from system as this cannot be hardcoded. IAP localized price also uses “zł” not “PLN”
I tried this way:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.currencySymbol = Locale.current.currencySymbol
formatter.maximumFractionDigits = 2
let price = formatter.string(from: (offeringPrice / 12) as NSNumber) ?? ""
but whatever I try to use as currency symbol I always get in return "PLN"
If you set formatter.locale to pl_PL it works:
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.maximumFractionDigits = 2
formatter.currencyCode = "PLN"
let polandLocale = Locale(identifier: "pl_PL")
let usLocale = Locale(identifier: "en_US")
let offeringPrice = 50.0
let price = (offeringPrice / 12) as NSNumber
formatter.locale = usLocale
formatter.string(from: price) // "PLN 4.17"
formatter.locale = polandLocale
formatter.string(from: price) // "4,17 zł"
I've found this solution
func getCurrencySymbol(from currencyCode: String) -> String? {
let locale = NSLocale(localeIdentifier: currencyCode)
if locale.displayName(forKey: .currencySymbol, value: currencyCode) == currencyCode {
let newlocale = NSLocale(localeIdentifier: currencyCode.dropLast() + "_en")
return newlocale.displayName(forKey: .currencySymbol, value: currencyCode)
}
return locale.displayName(forKey: .currencySymbol, value: currencyCode)
}
original answer here: https://stackoverflow.com/a/49146857/1285959
How to convert number formate with separated by ,
Example
Resultant String
"38963.26" value into "38,863.26"
"1013321.22" Value into "10,13,321.22"
//MARK:- Seperator number formate 1000 - 1,000
extension Formatter {
static let withSeparator: NumberFormatter = {
let formatter = NumberFormatter()
formatter.groupingSeparator = ","
formatter.numberStyle = .decimal
return formatter
}()
}
extension BinaryFloatingPoint {
var formattedWithSeparator: String {
return Formatter.withSeparator.string(for: self) ?? ""
}
}
let resultValue = StringValue.CGFloatValue()?.formattedWithSeparator
print("Resultant", resultValue!)
CGFloatVaule default method for converting String to floatValue.
same like String.floatValue.
For value "38963.26" is gives resultant value "38,963.262" I wonder why its like that extra 2 in decimal.
print("38963.26".CGFloatValue()!.formattedWithSeparator)
Output "38,863.262"
Either set a proper (that uses this style for formatting) locale or set both decimal and grouping separator on your formatter instance since not all Locale might use the same separators.
Then you also need to set max number of fraction digits if you are using float (for some reason this isn't needed for Double)
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "en_US")
formatter.maximumFractionDigits = 2
if let str = formatter.string(for: Float(numberString)) {
print(str)
}
let formatter = NumberFormatter()
formatter.groupingSeparator = ","
formatter.decimalSeparator = "."
formatter.numberStyle = .decimal
formatter.maximumFractionDigits = 2
if let str = formatter.string(for: Float(numberString)) {
print(str)
}
Both yields
38,963.26
Refer this:-
how to add commas to a number in swift?enter link description here
let numberFormatter = NumberFormatter()
numberFormatter.numberStyle = .decimal
let numberString = "38963.26"
if let number = Double(numberString),
let formattedNumber = numberFormatter.string(from: NSNumber(value: number)) {
let formattedString = "\(formattedNumber)"
print(formattedString)
}
There are three issues:
The use of explicit grouping separator.
Forcing the thousands separator to “,” is counterproductive. If the device is in a locale where that’s already the default, you don’t need to specify it. And if the device is in a locale where it’s not default, it will be exceedingly confusing for a user who is not used to seeing “,” thousandths separators. And worse, if you were to override the grouping separator, you should also override the decimal separator, too. If this is for a string to be presented in the user interface, I would suggest not touching the grouping separator (or any of those properties):
static let decimal: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
return formatter
}()
If you really want to force use , for grouping separator and . for decimal separator (even though the user might be in a locale where that might be exceeding confusing were you to present that in the user interface), you should go ahead and change the locale to whatever you want, e.g.
static let decimal: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.locale = Locale(identifier: "en_US") // or "en_IN" or whatever
return formatter
}()
Decimal places.
If you always want two decimal places, then:
static let decimal: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
formatter.minimumFractionDigits = 2
formatter.maximumFractionDigits = 2
return formatter
}()
By setting minimum fraction digits, you’re ensured that 42.1 will show up as “42.10”. By setting maximum fraction digits, you’re ensured that 42.33333 will show up as “42.33”.
Issues resulting from conversion of string to binary floating point and back to string.
The fundamental problem with the decimal places is that you’re converting a string to a binary floating point number. If you use Double, you’ll capture more significant digits than you will with Float/CGFloat, but you’re still introducing rounding errors as you convert a string to a binary floating point representation. Float starts introducing conversion errors at the 7th significant decimal digit. Double defers the conversion errors to the 15th significant decimal digit.
You might consider using a numeric format that will capture up to 38 digits without rounding issues, namely Decimal. Thus:
extension NumberFormatter {
static let decimal: NumberFormatter = {
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
// specify locale and/or fraction digits as needed
return formatter
}()
}
extension String {
func decimalFormatted() -> String? {
return Decimal(string: self).flatMap { NumberFormatter.decimal.string(for: $0) }
}
}
And then
let string = "38963.26"
let foo = string.decimalFormatted() ?? ""
I am using following code to convert string to US currency. However, I could not figure out how to disable round up.
For example, if the string value is "0.000012" code converts it to "$0.00".
The extension I am using it is from this SO answer:
The way I use:
print(Formatter.currency.locale) // "en_US (current)\n"
print(priceUsdInt.currency) // "$1.99\n"
To control rounding (accept 6 digits after point in this case) add formatter.maximumFractionDigits = 6; to your Formatter extension
extension Formatter {
static let currency = NumberFormatter(style: .currency)
static let currencyUS: NumberFormatter = {
let formatter = NumberFormatter(style: .currency)
formatter.locale = Locale(identifier: "en_US")
formatter.maximumFractionDigits = 6;
return formatter
}()
static let currencyBR: NumberFormatter = {
let formatter = NumberFormatter(style: .currency)
formatter.locale = Locale(identifier: "pt_BR")
formatter.maximumFractionDigits = 6;
return formatter
}()
}
0.000012 is should NOT convert to 0.01 , that would be wrong.
If you want to set up a different format you can change the decimal points
String(format: "%0.3f", string)