Xcode11からja_JPロケールのNumberFormatter出力でnbspが入るようになった
事の発端
元々以下のように数値を通貨形式の文字列フォーマットに変換する処理のユニットテスト書いてあったんだけど、Xcode11にしてからテストが失敗するようになってしまった。
let target = 1000 XCTAssertEqual(target.yenFormattedString, "1,000円") // "1,000 円" is not equal "1,000円"
ちなみに、ここでやっている .yenFormattedString
は以下のようなIntのExtension。
extension Int { var yenFormattedString: String { let formatter = NumberFormatter() formatter.locale = Locale(identifier: "ja_JP") formatter.numberStyle = .currencyPlural return numberFormatter.string(from: self as NSNumber) ?? "" } }
"1,000 円" is not equal "1,000円"
と言われているので、円
の前に半角スペース入るように変わったのかな?と思い、テストを修正してみたら以下のようになった。
let target = 1000 XCTAssertEqual(target.yenFormattedString, "1,000 円") // "1,000 円" is not equal "1,000 円"
"1,000 円" is not equal "1,000 円"
??
文字コード調査
これは普通の半角スペースじゃなくなんか謎の文字が入ってるのでは?と考え、エラーになった文字列をコピーしてodコマンドで確認してみたら以下のような違いが発覚。
# 通常の半角スペース $ echo "1,000 円" | od -tx1 -a 0000000 31 2c 30 30 30 20 e5 86 86 0a 1 , 0 0 0 sp 86 86 nl # NumberFormatter出力 $ echo "1,000 円" | od -tx1 -a 0000000 31 2c 30 30 30 c2 a0 e5 86 86 0a 1 , 0 0 0 86 86 nl
0x20
が通常の半角スペースだけど、今回の出力結果は 0xC2A0
だった。
0xC2A0
ググってみたらnbsp(Non-Breaking SPace)とのこと。
  は半角スペースではないというお話 (フェンリル | デベロッパーズブログ)
他ロケールでは元々起きていたらしい
もうちょっと調べてみたら、ユーロなどの通貨では結構前から同じことになっていたらしい。
【追記】XCTAssertEqualが("foo bar") is not equal to ("foo bar")などと寝ぼけたことを言う【NSNumberFormatter】 - DRYな備忘録
iphone - NSNumberFormatter, how to remove blank spaces in currency symbol - Stack Overflow
確かに手元のXcode10系で試したら同じようになった。 Xcode11からja_JPロケールもこれと同じ動きになった模様。
バグなのか仕様なのか🤔
通貨表現だから、UILabelなどで勝手にそこでワードラップされないようにnbspになっていると考えれば、理に適ってるのかもしれない。
ただちょっと正式にこういう仕様になったのかどうかのドキュメント見つけられていないので、誰か知ってたら教えてくださいm( )m
とりあえず現状はテストの期待結果にnbsp入れてテストを通してる。