電卓の数字入力のキューを整理していたら、バグがあることがわかりました。
以下がキューのPush,PoPの結果です。
よくよく見ると小数点下1桁を消したところで整数とすべきところ、小数点だけが残ってしまっています。ここをどうにかしなくてはいけません。
以下がPush、Popの操作部です。ここをいじるようではだめですね。ここはまったくいじりません。
以下がNumberQueueクラスの主要部です。まだ機能は全て実装していないですが、PushとPopは実装しています。
Popに小数点処理やフォーマッターを入れ忘れています。
フォーマッターを2つは作りたくないので、Pushと同じフォーマッターを入れてみます。
結果はこんな感じです。
6を消したあと12,345になるのはいいですが、裏で動いているキューの小数点が消えていないので、もう一回popしたときにも同じ数字がでている点が一つ、
もう一つは、最後にnil処理が実装されておらず、Fatal errorが出ているところですね。
これらを修正していきます。
まず前者からですが、これはフォーマッタ(表示)の問題ではないので、小数点下一桁でのPopで小数点も消す処理は、Pop側で実装します。
ここでは、キューをPopして取り出した文字列の最後が小数点の場合に、小数点を削除する処理を入れました。
ただし、単に取り出した文字列を削除するだけではだめで、表示用のフォーマッターの小数点以下の桁をゼロにして、さらにキュー本体からも小数点を削除してあげなければダメでしたので、その処理を組み込んでいます。
しかし、表示処理をキューの機能に持たせるのはおかしいですね。
そこでフォーマッターの処理をみてみました。
フォーマッターの処理としては、小数点があったときだけ小数点以下の数値を変えていました。そのため、以前に小数点以下1桁の数値が入ったあとに、小数点のない数値が入ると小数点1桁のままで表示してしまう、というフォーマッターのバグであることがわかりました。
あと、後者のエラーは、フォーマッターで強制アンラップ(!)している部分でnilの処理が走ったためとわかり、オプショナルバインディングでnil処理を加えました。
結果フォーマッターとpop処理を次のように変更しした。
formatter
pop処理
実行結果
いやぁ、バグがとれてスッキリです。しかしSwiftは予想以上に洗練された言語なのがわかりますね。非常に感心しました。
以下がキューのPush,PoPの結果です。
1
12
123
1,234
12,345
12,345
12,345.6
12,345.67
12,345.678
12,345.6789
12345.678
12345.67
12345.6
12345.
12345
1234
123
12
1
よくよく見ると小数点下1桁を消したところで整数とすべきところ、小数点だけが残ってしまっています。ここをどうにかしなくてはいけません。
以下がPush、Popの操作部です。ここをいじるようではだめですね。ここはまったくいじりません。
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
// キューの生成
let numberQueue = NumberQueue()
// 数字のPush
for i in 0...5 {
numberQueue.push(String(i))
}
// 小数点のPush
numberQueue.push(".")
// 数字のPush
for i in 6...9 {
numberQueue.push(String(i))
}
// キューのPop
for _ in 0...10{
numberQueue.pop()
}
}
}
以下がNumberQueueクラスの主要部です。まだ機能は全て実装していないですが、PushとPopは実装しています。
class NumberQueue{
/* 0..9 "." のString型を入力とする電卓数字用のキュー
表示とのセットで汎用化はしない。
特殊機能:キューの初期化ととテーブルへの格納のための初期化コマンドを備える*/
// property
let formatter = NumberFormatter()
// キューの生成と初期化
let queue = Queue()
// end property
// init
init(){
// スタイルを指定
formatter.numberStyle = .decimal
// 数値の区切り文字を指定する
formatter.groupingSeparator = ","
// 何桁ごとに区切り文字を入れるか指定する
formatter.groupingSize = 3
// 言語・地域
formatter.locale = Locale(identifier:"ja_JP")
}
// end init
// functions
func formattedNumberString(_ val:String)->String{
if let range = val.range(of: "."){
let underDicimal = val.count - 1 -
val.distance(from: val.startIndex, to:range.lowerBound)
formatter.minimumFractionDigits = underDicimal
}
let doubleValue = Double(val)
let nsNumberValue = NSNumber(value: doubleValue!)
let numberString = String(formatter.string(from: nsNumberValue)!)
return numberString
}
func push(_ s:String){
if let c = changeString2Character(s){
if let val = queue.push(c){
let numString = formattedNumberString(val)
print(numString)
}
}
}// push
func pop(){
let p = queue.pop()
if let s = p.s {
print(s)
}
}
// end functions
}// end NumberQeue
Popに小数点処理やフォーマッターを入れ忘れています。
フォーマッターを2つは作りたくないので、Pushと同じフォーマッターを入れてみます。
func pop(){
let p = queue.pop()
if let s = p.s {
let numberString = formattedNumberString(s)
print(numberString)
}
}
結果はこんな感じです。
1
12
123
1,234
12,345
12,345
12,345.6
12,345.67
12,345.678
12,345.6789
12,345.678
12,345.67
12,345.6
12,345
12,345
1,234
123
12
1
Fatal error: Unexpectedly found nil while unwrapping an Optional value
2019-07-13 09:20:28.044385+0900 Prototype[6835:575272] Fatal error: Unexpectedly found nil while unwrapping an Optional value
6を消したあと12,345になるのはいいですが、裏で動いているキューの小数点が消えていないので、もう一回popしたときにも同じ数字がでている点が一つ、
もう一つは、最後にnil処理が実装されておらず、Fatal errorが出ているところですね。
これらを修正していきます。
まず前者からですが、これはフォーマッタ(表示)の問題ではないので、小数点下一桁でのPopで小数点も消す処理は、Pop側で実装します。
func pop(){
let p = queue.pop()
if let s = p.s {
var queueString = s
if queueString.suffix(1) == "." {
queueString = String(queueString.prefix(queueString.count - 1))
formatter.minimumFractionDigits = 0
let _ = queue.pop()
}
let numberString = formattedNumberString(queueString)
print(numberString)
}
}
ここでは、キューをPopして取り出した文字列の最後が小数点の場合に、小数点を削除する処理を入れました。
ただし、単に取り出した文字列を削除するだけではだめで、表示用のフォーマッターの小数点以下の桁をゼロにして、さらにキュー本体からも小数点を削除してあげなければダメでしたので、その処理を組み込んでいます。
しかし、表示処理をキューの機能に持たせるのはおかしいですね。
そこでフォーマッターの処理をみてみました。
フォーマッターの処理としては、小数点があったときだけ小数点以下の数値を変えていました。そのため、以前に小数点以下1桁の数値が入ったあとに、小数点のない数値が入ると小数点1桁のままで表示してしまう、というフォーマッターのバグであることがわかりました。
あと、後者のエラーは、フォーマッターで強制アンラップ(!)している部分でnilの処理が走ったためとわかり、オプショナルバインディングでnil処理を加えました。
結果フォーマッターとpop処理を次のように変更しした。
formatter
func formattedNumberString(_ val:String)->String?{
formatter.minimumFractionDigits = 0
if let range = val.range(of: "."){
let underDicimal = val.count - 1 -
val.distance(from: val.startIndex, to:range.lowerBound)
formatter.minimumFractionDigits = underDicimal
}
if let doubleValue = Double(val){
let nsNumberValue = NSNumber(value: doubleValue)
if let formatterString = formatter.string(from: nsNumberValue){
return String(formatterString)
}
else{
return nil
}
}
else{
return nil
}
}//formattedNumberString
pop処理
func pop(){
let p = queue.pop()
if let s = p.s {
var queueString = s
if queueString.suffix(1) == "." {
queueString = String(queueString.prefix(queueString.count - 1))
let _ = queue.pop()
}
if let numberString = formattedNumberString(queueString){
print(numberString)
}
}
}
実行結果
1
12
123
1,234
12,345
12,345
12,345.6
12,345.67
12,345.678
12,345.6789
12,345.678
12,345.67
12,345.6
12,345
1,234
123
12
1
いやぁ、バグがとれてスッキリです。しかしSwiftは予想以上に洗練された言語なのがわかりますね。非常に感心しました。
0 件のコメント:
コメントを投稿