[iOS] \dの正規表現は全角数字もヒットする

2020.10.15

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。きんくまです。 小ネタです。

半角数字をチェックしようと思いました。そのときに正規表現を使ったのですが、 \d を使ったところ全角数字もヒットすることがわかりました。

チェック部分

class NumberValidator {
    
    /// 半角数字のみかチェックする
    /// - Parameter numString: 調べたい文字列
    /// - Returns: 半角数字のみであればtrue。そうでなければfalse
    static func isHalfWidthNumberString(_ numString: String?) -> Bool {
        guard let numStr = numString else {
            return false
        }
        if numStr.isEmpty {
            return false
        }
        
        let count = numStr.count
        
        // \dを使ったパターン
        let pattern = "\\d{\(count)}"
        
        return numStr.range(of: pattern, options: .regularExpression) != nil
    }
}

テストコード

    func test_isHalfWidthNumberString() {
        XCTContext.runActivity(named: "半角文字のみならtrue") { _ in
            var result = NumberValidator.isHalfWidthNumberString("0123456789")
            XCTAssertTrue(result)
            result = NumberValidator.isHalfWidthNumberString("0")
            XCTAssertTrue(result)
            result = NumberValidator.isHalfWidthNumberString("2357")
            XCTAssertTrue(result)
        }
        XCTContext.runActivity(named: "空文字またはnilならfalse") { _ in
            var result = NumberValidator.isHalfWidthNumberString("")
            XCTAssertFalse(result)
            result = NumberValidator.isHalfWidthNumberString(nil)
            XCTAssertFalse(result)
        }
        XCTContext.runActivity(named: "全角文字のみならfalse") { _ in
            var result = NumberValidator.isHalfWidthNumberString("0123456789")
            XCTAssertFalse(result)
            result = NumberValidator.isHalfWidthNumberString("1")
            XCTAssertFalse(result)
        }
        XCTContext.runActivity(named: "半角全角文字まざっていたらfalse") { _ in
            var result = NumberValidator.isHalfWidthNumberString("01234567890123456789")
            XCTAssertFalse(result)
            result = NumberValidator.isHalfWidthNumberString("11")
            XCTAssertFalse(result)
        }
        XCTContext.runActivity(named: "数字以外ならfalse。混じっていてもfalse") { _ in
            var result = NumberValidator.isHalfWidthNumberString("あいうえお")
            XCTAssertFalse(result)
            result = NumberValidator.isHalfWidthNumberString("0123あいうえお")
            XCTAssertFalse(result)
            result = NumberValidator.isHalfWidthNumberString("abcd")
            XCTAssertFalse(result)
            result = NumberValidator.isHalfWidthNumberString("abcdあいう")
            XCTAssertFalse(result)
            result = NumberValidator.isHalfWidthNumberString("0123abc")
            XCTAssertFalse(result)
            result = NumberValidator.isHalfWidthNumberString("0123abcd")
            XCTAssertFalse(result)
        }
    }

こちらを実行するとこのように、全角数字のところでエラーになりました。

正規表現のパターンを修正する

\d ではなくて [0-9] の方にしてみます。

下のコードはパターン以外は最初と全く同じです。

class NumberValidator {
    
    /// 半角数字のみかチェックする
    /// - Parameter numString: 調べたい文字列
    /// - Returns: 半角数字のみであればtrue。そうでなければfalse
    static func isHalfWidthNumberString(_ numString: String?) -> Bool {
        guard let numStr = numString else {
            return false
        }
        if numStr.isEmpty {
            return false
        }
        
        let count = numStr.count
        
        // [0-9]を使ったパターン
        let pattern = "[0-9]{\(count)}"
        
        return numStr.range(of: pattern, options: .regularExpression) != nil
    }
}

テストが通った!

無事にテストが通りました!やったー!

感想

テスト書いたら気がついたので、こういうときはやっぱり書いた方が良いなと思いました。