今回は、前回から眺めはじめた UIKit
にまつわるチップス集的な技術ブログと思われる「同じような処理だけどこっちの方がいいよってやつ」から、数字の文字列変換とか
から続けて見ていきますね。話題的に UIKit
に寄ったものになりますけれど、せっかくの Swift 勉強会なので Swift 的な観点も踏まえて紹介できたらいいなと思っています。よろしくお願いしますね。
——————————————————————————————————————— 熊谷さんのやさしい Swift 勉強会 #287
00:00 開始 00:53 数値を文字列に変換する 01:11 NumberFormatter で桁区切りする 04:42 GitHub Copilot に聞いてみる 06:20 いろいろな国の桁区切り記号 08:48 数値表現はロケール設定で調整するのを推奨 10:14 通貨単位を加味した表現 11:13 数値はそのまま通貨単位だけ変わるので要注意 11:54 通貨単位での詐欺に注意 16:03 通貨単位を固定する方法 18:05 さまざまなフォーマッターが用意されている 19:15 ByteCountFormatter 22:00 いくつかのサイズ表現 23:28 SI 接頭語と2進接頭辞 25:23 キロバイトを kB と KB で区別していた時代 27:44 バイト数表現は慣れが必要そう 30:14 バイト単位での値も併記する書式 30:49 表示に使う単位を制限する 32:10 decimal と binary が推奨されるらしい 32:44 ファイルサイズの慣用表現が変わる可能性も考慮すると 33:22 decimal は 10 進数基準、binary は 2 進数基準 34:48 配列をよしなに表現するフォーマッター 36:36 さまざまな単位を表現するための仕組み 38:40 ほかにもいろんなフォーマッターがある様子 39:38 RelativeDateTimeFormatter ってなんだろう 42:15 クロージングと次回の展望 ———————————————————————————————————————
Transcription & Summarize : 熊谷さんのやさしい Swift 勉強会 #287
では始めていきますね。こちらの面白そうなブログ記事がありますので、今回はそれを元に進めていきたいと思います。このブログはのっぺーさんという方が書いていて、2022年1月に更新されたものです。少し古めの情報かもしれませんが、現在も十分に参考になる内容なので、記事をベースに見ていきたいと思います。
今回見ていくテーマは「数字の文字列変換」です。このテーマは少し曖昧に感じるかもしれませんが、具体的には NumberFormatter
を使って数字をフォーマットする方法についてです。NumberFormatter
を使えば、よく見る3桁ごとにカンマで区切られた形式の数字を簡単に生成することができます。
まず、基本的なサンプルコードから見ていきましょう。
import Foundation
let value = 1234567.89
let formatter = NumberFormatter()
formatter.numberStyle = .decimal
if let formattedString = formatter.string(from: NSNumber(value: value)) {
print(formattedString) // 出力: 1,234,567.89
}
このコードは非常によく使われるもので、NumberFormatter
を使って数値を文字列に変換します。上記の出力例では、ご覧のように3桁ごとにカンマで区切られた形式になっています。
また、NumberFormatter
にはデフォルトの値としてカンマ区切りの設定がされていますが、カスタマイズも可能です。例えば、カンマの代わりに別の文字を使用することもできます。次のように書けます。
formatter.groupingSeparator = " "
この例では、3桁ごとの区切り文字をスペースに変更しています。しかし、通常はこれを行うことは少なく、特定のロケールに応じたフォーマットを使用する方が一般的です。例えば、スイスのロケールで設定する場合は次のようにします。
formatter.locale = Locale(identifier: "de_CH")
これにより、カンマの代わりにドットを使用するフォーマットに変更されます。また、GitHub Copilotなどのツールを使ってこれをサポートする場合、適切なロケール識別子を選択するためにコメントを追加することも考えられます。例えば:
// スイスのロケールを設定する
このようにコメントを加えることで、コードが更に読みやすくなります。今回はこれで終了です。次回もこの調子で進めていきますので、よろしくお願いします。 さて、ここまでロケール設定についていろいろと見てきましたが、「ロケール」とは地域設定を指し、数値フォーマットや日付フォーマットなどを指定する際に使用します。今回は Swift を使ってその設定方法を学びました。
まず、ロケールを設定した状態での挙動についてですが、特定のロケールを設定すると、それに応じた数値や日付の表現形式が利用されます。これによって、地域ごとの表示形式に対応することができるので、非常に便利です。ただし、このロケール設定によっては、意図しないフォーマットになることもあります。
たとえば、数値のグルーピングセパレーターとしてアポストロフィーを使う国がある一方で、シングルクォートが使用されることもあります。この設定次第では、表示面で違和感を覚えることもあるため、場合によっては明示的に指定することも考えるべきです。
また、NumberFormatter
を使って数値を特定の形式で表示する方法も紹介されました。例えば、ナンバースタイルを decimal
に設定して小数点以下の桁数を調整したり、カレンシースタイルを使用して通貨表記するなどの方法があります。以下は、実際の利用例です。
let formatter = NumberFormatter()
formatter.numberStyle = .currency
formatter.locale = Locale(identifier: "ja_JP") // 日本円の形式に設定
let formattedString = formatter.string(from: 1000) // 例: "¥1,000"
このようにして、特定の通貨形式に変換することができます。ただし、異なるロケールを設定すると、同じ値でも異なる表示形式となるため注意が必要です。例えば、アメリカドル形式にする場合も、同様に設定を変更します。
また、ロケールによっては詐欺に遭遇する可能性もあります。たとえば、外国のサイトで日本語表示になっているにもかかわらず、表示されている通貨が日本円ではなかったり、その換算レートが不当なものであったりすることがあるので注意が必要です。
このように、ロケール設定やフォーマッターの利用方法を正しく理解して、適切に利用することが重要です。特に、アプリケーションのインターフェースやバックエンドのAPI連携でしっかりと対策を講じるべきです。総じて、ユーザーにとって使いやすいアプリケーションを提供するために、ロケールを効果的に利用し、適切な表示形式を維持することが求められます。 でも、どこか人民権表示になることは多いですね。それが詐欺さえなければね。秋葉原は住みやすいとは思いますが、詐欺があると、日本で100円のものを2000円で売りつけられるようなことが起こりかねません。相手が2000円で売ることを想定して値段設定をしてくる、そういった詐欺になりかねないので注意が必要です。目で見て判別しにくいので、充分注意しましょう。
さて、本題に戻ります。今回話したいのはナンバーフォーマッターの話です。ここで、値段の表示の仕方について触れていきます。例えば、CurrencyDecimalSeparator
、CurrencyGroupingSeparator
、CurrencySymbol
、CurrencyCode
などがあります。これらを使いこなすと、異なる通貨を正しく表示できますね。
実際使うときに調べて進めていくのが良いと思いますが、Currency
に関する設定はそれほど頻繁には使わないかもしれません。ただし、国別の通貨記号や小数点などを適切に表示するためには、そのあたりをしっかり設定する必要がありますね。ロケールをちゃんと指定しておけば、変な結果が出ることはないですから、確かに良いかもしれません。例えば、ドイツ向けの通販サイトを作る際には、ドイツの通貨ユーロを表示することが求められます。
キーボードで異なる通貨記号を表示する場合、例えばポンド記号(£)はどのキーで出るのか、といった話もあります。まあ、こういったことはナンバーフォーマッターを使って適切に処理すれば良いでしょう。
ナンバーフォーマッターを使えば、数字の文字列変換が簡単に行えます。例えば、日時についても、ISO8601形式の日付フォーマッターを使えば便利です。APIからのデータを扱う際などに有用です。
ナンバーフォーマッターの他にも、バイトフォーマッターというものがあります。これは、データのサイズを適切に表示するためのものです。例えば、300メガバイト以上ならギガバイトで表示するといった具合です。プログラムでこれをハンドリングするのは少し大変ですが、バイトカウントフォーマッターを使えばこれを簡単に行ってくれます。
具体的なコードとしては、次のようになります:
let byteCountFormatter = ByteCountFormatter()
byteCountFormatter.allowedUnits = [.useGB] // 表示単位はギガバイト
byteCountFormatter.countStyle = .binary
let fileSize = 300 * 1024 * 1024 // 300メガバイト
let formattedSize = byteCountFormatter.string(fromByteCount: Int64(fileSize))
print(formattedSize) // 例えば "0.29 GB" と表示される
このように、バイトカウントフォーマッターを使うことで、データサイズの表示が非常に簡単かつ正確に行えます。いろいろなスタイルや単位で表示できますので、使ってみると面白いですよ。今まで頑張ってプログラムで処理していた部分が、簡単に置き換えられるかもしれませんね。 バイトカウントフォーマッターの stringFromByteCount
メソッドを使ったときに、微妙な結果が出ることがあります。例えば、1024のバイト数をフォーマットするときに、1.02テラバイト
と表示されたとします。この結果はバイナリーのときに正確に表現されていない可能性があります。計算を確認すると、1024を1000倍しているのでおかしいですね。適切に計算すれば、1ギガバイトのファイルが 1.07ギガバイト
になるのです。
また、ディスクストレージにおいては容量が少し増して表示されることがあります。通常、メガバイト(MB)は1024バイトで計算しますが、例えば2ギガバイト(GB)の場合は1000バイト単位で計算されることがあります。ディスクのストレージはこのようにかさ増しされることが一般的です。そのため、ディスクの容量が 1.07ギガバイト
と表示されても、実際にファイルが1ギガバイト分しか入らないことがあります。パーティションを作成するときも同じ状況が起こります。
さらに、メビバイト(MiB)という単位についても言及しました。以前はすべてメガバイト(MB)と呼ばれていたため、混乱を避けるためにメビバイトという新しい表記が生まれました。メビバイト(MiB)は1024キビバイト(KiB)に相当します。このようにコンピューターの容量やデータの大きさを表す新しい単位が使われています。
メモリーサイズは通常、バイナリー(2進)接頭辞を使いますが、ディスクストレージについてはSI接頭辞を使うことが一般的です。この違いはフォーマットやその他の要因によるものかもしれません。
また、昔の話として、キロバイト(KB)という単位について触れました。以前はキロバイトと書かれると1000倍のキロを意味していましたが、コンピューターの分野では1024バイトを表すために大文字のK
を使うなどの工夫がありました。今ではキロバイトに代わり、キビバイト(KiB)が使用されています。これは、1キビバイトが2の10乗、つまり1024バイトに相当するためです。こうした区別は国際単位系などの影響を受けています。
以上が、この部分の内容です。他の記事や情報源を参照することで、より詳細な背景や歴史を知ることができます。 なるほど、そのようなことがあったんですね。ファイルとファイナリですが、確かに分かりにくいですよね。どっちがどっちか分かると言えば分かるけど、もう少しわかりやすくする方法もありそうです。
デシマルについても考えてみましょう。デシマルは点を使用するので、その点は確かに大切ですね。そしてメモリが1024です。なるほど、ファイナリとメモリの関係ですね。デシマルとファイナリと同じように、メモリとファイルという構成です。
具体的な例として si
を使う場合など、どうにもならないケースがあります。そうすると、慣れの問題かもしれませんね。具体的な方が後悔が少ないのかもしれません。何にしても便利な機能ですね。例えば、バイナリ表示に関しても、1ギガバイトが表示されることについて好みが分かれると思います。
例えば、100メガバイトが100メガバイトと表示される場合、400メガバイトなら400メガ、800メガバイトなら800メガと出ますが、900メガバイトの場合に1ギガバイトとして揃えることができるのでしょうか?オプションで設定できるかもしれません。具体的には 0.9
ギガバイトと出したいような場合ですね。
allowedUnits
のオプションを使うことで、バイトカウントの表示が可能です。例えば、ストリングの前に設定しておくと、バイト数が正確に表示されます。以下のコードを例に示します:
let byteCountFormatter = ByteCountFormatter()
byteCountFormatter.allowedUnits = [.useMB, .useGB]
let formattedString = byteCountFormatter.string(fromByteCount: 880 * 1024 * 1024)
print(formattedString) // 0.88GB と表示される
コメントで「デシマルとバイナリーは推奨されている」とのことですね。バイナリーは推奨されて、ファイルは推奨されていないと理解しました。時代によって推奨されるフォーマットが変わるので、その時々で適したものを使うのが良いでしょう。
昔の Mac は確かバイナリーフォーマットを使用していました。時代が進むにつれてファイルフォーマットが推奨されるようになり、新しいフォーマットが適用される場合があります。
最後に、インクルードカウントやアクチュアルバイトカウントなど、色々なフォーマッターがあります。以下のコードでそれらを検証できます:
byteCountFormatter.includesActualByteCount = true
let detailedString = byteCountFormatter.string(fromByteCount: 1024)
print(detailedString) // "1 KB (1,024 bytes)" と表示される
こういった機能を使って表示を調整すると、よりユーザーフレンドリーなインターフェースを提供できますね。 最後に「アウト」をつけていますね。そうなんだ、最後に入るのがA、B&Cみたいな感じですね。そうそう、あれか、そういうことですね。
これ、すごいですね。これもやってみたいことがありますよね。前にちょっとね。えー、知る人ぞ知るって感じなんですね。パーセント表記、これはNumberFormatter。あと、そのままフォーマッターもありますね。パーセントとかにも対応していますね。他にもたくさんのコンポーネントフォーマッターがあって面白いですね、確かに。
「ハローヤマダ」とかにするかみたいな感じのもありますね。そういう微妙に悩まされるやつです。でもこれ使えば標準で対応できる感じで、悩まされずに作れますね。あとこの単位のフォーマッター、使ったことはないですが便利そうだなと思っていました。どなたかが紹介していたと思います。単位を自分で作ったりもできるらしいですよ、確か。
フォーマッターには単位変換などもいろいろとできる機能がありますね。詳しく見たことはないのですが、MeasurementFormatterだけでなく、その元になるブロックも確かあったと思います。こんなフォーマッターを使って工夫を凝らすと、良いコードが書けそうですね。これも使えそうです。
ReferenceTypeについてちょっと見てみましょう。あ、これはObjective-Cブリッジですね。これは置いといて、昔からあるObjective-Cブリッジです。
単位と値のどちらかがあって、イニシャライザーがあり、ハッシュやEquatableなどが使えますね。これで良い感じに単位を表現して、異なる単位が混ざることなくちゃんと使えるようになりますね。ただし、しっかり理解していないと使いにくいかもしれませんが、基本的なことですね。
このコンバート機能は色々とやってくれるみたいです。私も詳しくは知らないので、どこまで柔軟性があるのかは分かりませんが、興味があれば試してみると面白いかもしれません。
他にもフォーマッターが色々ありますね。例えばEnergyFormatter、LengthFormatterなどたくさんあります。DateIntervalFormatterは名前からして便利そうに感じます。パフォーマンスを継続した時などに使えそうな予感がします。まだ中身を見ていないので、しっかり確認する必要がありますが。
NativeのDateTimeFormatterもありそうです。これも良さそうですね。後で見てみましょう。でもこの後はCoreFoundationに行ってしまいますね。これはネイティブではないので。面白いですね。
DateIntervalFormatterについてもう少し触れましょうか。これで二つの日時をフォーマットするのでしょうか。カレンダーやタイムゾーン、時間スタイルなどを設定して、string(from: startDate, to: endDate)
のように使います。例えば変数をインスタンス化して使うと良いでしょう。
例えば、let formatter = DateIntervalFormatter()
として、色々と設定してみましょう。1970年から現在までの期間を表示するようにすると、こう表示されます。これで適切にフォーマット指定をすれば、詳細を調整することもできます。
今日は時間がそろそろ無いので、この辺りで一旦終わりにしましょう。次回も引き続き数字の文字列変換について見ていきましょう。次回の勉強会もお楽しみに。それでは、今日の勉強会はこれで終了します。お疲れ様でした。