Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SR-11970] NumberFormatter adding extra space for specific locale #4483

Open
swift-ci opened this issue Dec 19, 2019 · 4 comments
Open

[SR-11970] NumberFormatter adding extra space for specific locale #4483

swift-ci opened this issue Dec 19, 2019 · 4 comments

Comments

@swift-ci
Copy link
Contributor

Previous ID SR-11970
Radar rdar://problem/58455075
Original Reporter kbrady1 (JIRA User)
Type Bug
Additional Detail from JIRA
Votes 0
Component/s Foundation
Labels Bug, Locale, NumberFormatter
Assignee None
Priority Medium

md5: dee947fbd2245f52d105d50d813b12ef

Issue Description:

When using NumberFormatter to create a currency number format with a number style of currency and a locale of "en_US_POSIX" an extra space is being added between the dollar sign and the number.

let formatter = NumberFormatter()
formatter.locale = "en_US_POSIX"
formatter.numberStyle = .currency

//This returns "$ 3.14"
let currency = formatter.string(from: NSNUmber(floatLiteral: 3.14))

However, using that same formatter to change the string back into a double will return nil

//Using a formatter with the same configuration as above

//This returns nil
let currencyValue = formatter.number(from: "$ 3.14")

Using the "en_US" locale will not put a space between the dollar sign and numbers.

@beccadax
Copy link
Contributor

beccadax commented Jan 9, 2020

@swift-ci create

@spevans
Copy link
Collaborator

spevans commented Jan 15, 2020

Im not sure why the space is added, thats probably down to the underlying ICU library however the reason the "$ 3.14" wont parse back is the that space is not a normal ASCII space (value 32) but a Unicode no break space (value 160). As the following shows:

import Foundationlet formatter = NumberFormatter()
formatter.locale = Locale(identifier: "en_US_POSIX")
formatter.numberStyle = .currency
print("Formatter.positiveFormat", formatter.positiveFormat!)//This returns "$ 3.14"
let formattedCurrency = formatter.string(from: NSNumber(floatLiteral: 3.14))!
print("formattedCurrency:", formattedCurrency)
let parsedValue = formatter.number(from: formattedCurrency)!
print("Parsing back to a number:", parsedValue)let str = "$ 3.14"
print("Parsing test string \"\(str)\" to a number:", formatter.number(from: str) ?? "nil")let str1 = "$3.14"
print("Parsing test string \"\(str1)\" to a number:", formatter.number(from: str1) ?? "nil")
print("Formatter.positiveFormat:", formatter.positiveFormat!.unicodeScalars.map { $0.value })
print("formattedCurrency:", formattedCurrency.unicodeScalars.map { $0.value })
print("Test string \(str)", str.unicodeScalars.map { $0.value }) 

gives

Formatter.positiveFormat ¤ #​0.00
formattedCurrency: $ 3.14
Parsing back to a number: 3.14
Parsing test string "$ 3.14" to a number: nil
Parsing test string "$3.14" to a number: 3.14
Formatter.positiveFormat: [164, 160, 35, 48, 46, 48, 48]
formattedCurrency: [36, 160, 51, 46, 49, 52]
Test string $ 3.14 [36, 32, 51, 46, 49, 52]

The difference in the byte sequences of the currency string show the 32 v 160.

Interestingly it appears to still correctly parse a string which has no space at all "$3.14"

@spevans
Copy link
Collaborator

spevans commented Jan 27, 2020

I had another look at this are it looks to be the difference between en_US and en_US_POSIX

$ cat sr-11970.swift 
import Foundation

let number = NSNumber(floatLiteral: 3.14)
let formatter = NumberFormatter()
formatter.numberStyle = .currency

formatter.locale = Locale(identifier: "en_US_POSIX")
print(formatter.locale.identifier, formatter.string(from: number) ?? "nil")

formatter.locale = Locale(identifier: "en_US")
print(formatter.locale.identifier, formatter.string(from: number) ?? "nil")

$ swift sr-11970.swift 
en_US_POSIX $ 3.14
en_US $3.14

I think you just need to use the en_US locale instead.

@swift-ci
Copy link
Contributor Author

Comment by Kent Brady (JIRA)

You are correct, @spevans, using the un_US locale does work properly. This is the current work around that I am using. However, this real issue is that the en_US_POSIX formatter is not working bilaterally.

Switching from a number to a string will result in a space after the dollar-sign: "$ 3.14"

formatter.string(from: NSNumber(floatLiteral: 3.14))

If I then use that same formatter to switch back to a number with the same string created by the formatter, it will return nil:

formatter.number(from: "$ 3.14")

To get the en_US_POSIX formatter to work when converting from string to number, I have to remove the space:

formatter.number(from: "$3.14")

Considering that these two formatters (mostly) have the same behavior, and that the en_US_POSIX formatter only accounts for a space when converting to a string, and only works without a space when converting from a string to a number, I assume the added space is unintentional.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
@shahmishal shahmishal transferred this issue from apple/swift May 5, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants