20
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

文字列が許可された文字かどうかをNSCharacterSetで判定する

Posted at

役に立つかどうかよくわからないTipsシリーズ

また今回も文字列の拡張に関することです

例えばテキストフィールドなどで入力された文字などに
入力値チェックをすることも多いかと思います

そこには「アルファベットしか入れられないよ」とか「数字だけだよー」とか
そういう仕様はよくあるんじゃないかと思います

それを実現する方法としては
例えば正規表現でチェックするという手段もありますし
他にも色々とありそうです

その中から今回は「キャラクターセット」で判定を行う方法で
String の拡張をしてみますね

ベースメソッドを用意する

挙動を実現するためのベースとなるメソッドです
3行だけでシンプルに書けました

extension String {

    public func isOnly(structuredBy chars: String) -> Bool {
        let characterSet = NSMutableCharacterSet()
        characterSet.addCharactersInString(chars)
        return self.stringByTrimmingCharactersInSet(characterSet).length <= 0
    }
}

このメソッドは
渡したcharsに書かれている文字列のみで自身が構成されているか
を返すメソッドです

例えば

"ABC".isOnly(structuredBy: "ABCDEF") // true
"ABC".isOnly(structuredBy: "BCDEFG") // false
"ABC".isOnly(structuredBy: "abcdef") // false 

最初の1行目は
文字列"ABC"は、"A""B""C""D""E""F"のいずれかのみで構成されているか?
ということですのでtrueを返します

2行目は
"BCDEFG"の中に"A"がないのでfalse

3行目は
大文字と小文字はちゃんと区別しますよーということです

ラッピングプロパティを作る

ベースメソッドだけ用意すれば、なんなりとできるのですが
よく使うパターンをラッピングプロパティとして用意しておけば便利です

これはアプリの仕様に合わせ、必要に応じて追加・削除をしてもらえばと思いますが
普段から使えるものとして以下を用意しました

extension String {

    /// 半角数字のみで構成されているかどうか
    public var isOnlyNumber: Bool {
        return self.isOnly(structuredBy: "0123456789")
    }
    
    /// 半角アルファベットのみで構成されているかどうか
    public var isOnlyAlphabet: Bool {
        return self.isOnly(structuredBy: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ")
    }
    
    /// 半角英数字のみで構成されているかどうか
    public var isOnlyAlphabetAndNumber: Bool {
        let chars = String.structureOfAlphabetAndNumber
        return self.isOnly(structuredBy: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
    }
}

プロパティ化しておくことで、可読性もよくなりますし、コードもすっきりします

"ABC".isOnlyNumber // false
"ABC".isOnlyAlphabetAndNumber // true

ただし、なんだかメソッド定義側が
ガチャガチャしてる気がします

もうひと手間足してみることにします

extension String {
    
    /// 数字
    public static let structureOfNumber = "0123456789"
    
    /// 小英字
    public static let structureOfLowercaseAlphabet = "abcdefghijklmnopqrstuvwxyz"
    
    /// 大英字
    public static let structureOfUppercaseAlphabet = structureOfLowercaseAlphabet.uppercaseString
    
    /// 英字
    public static let structureOfAlphabet = structureOfLowercaseAlphabet + structureOfUppercaseAlphabet
    
    /// 英数字
    public static let structureOfAlphabetAndNumber = structureOfAlphabet + structureOfNumber
    
    /// 半角数字のみで構成されているかどうか
    public var isOnlyNumber: Bool {        
        let chars = String.structureOfNumber
        return self.isOnly(structuredBy: chars)
    }
    
    /// 半角アルファベットのみで構成されているかどうか
    public var isOnlyAlphabet: Bool {
        let chars = String.structureOfAlphabet
        return self.isOnly(structuredBy: chars)
    }
    
    /// 半角英数字のみで構成されているかどうか
    public var isOnlyAlphabetAndNumber: Bool {
        let chars = String.structureOfAlphabetAndNumber
        return self.isOnly(structuredBy: chars)
    }
}

isOnly(structuredBy:)メソッドに渡すchars
Stringのクラス定数として小分けに定義しました

先ほどの3つのメソッドの中身が整理できました
"0123456789"を3回も書くなんて非効率でしたのでね

これらを用意することにより、
拡張性も少しだけあがりました
例えば半角英数字に加えて半角スペースも許可するならこんな感じのプロパティを用意します

extension String {
    
    public var isOnlyAlphabetAndNumberAndSpace: Bool {
        let chars = String.structureOfAlphabetAndNumber + " "
        return self.isOnly(structuredBy: chars)
    }
}

電話番号のような数字とハイフンのみを許可するなら

extension String {
    
    public var isOnlyNumberAndHyphen: Bool {
        let chars = String.structureOfNumber + "-"
        return self.isOnly(structuredBy: chars)
    }
}

こんな感じでしょうか

電話番号やメールアドレスなどの形式があっているかどうかのバリデーションチェックをするなら
やはり冒頭に書いたとおり正規表現を用いるなどする必要もありますが

入力された文字がまず許可していい値かどうかを判定する用途等であれば
これだけでなかなか強力な機能となります

20
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
20
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?