LoginSignup
43
39

More than 5 years have passed since last update.

文字列を全角/半角に変換する

Last updated at Posted at 2016-02-10

(追記)
@mono0926 さんからコメント頂きまして、Stringの関数であるapplyingTransform(_:reverse) を使うと同様のことができるようです!
iOSなら9+で使えるので、CFString系を扱わずに済むかと思います。
以下コメント原文ママ

"アケマシテオメデトウゴザイマス".applyingTransform(.fullwidthToHalfwidth, reverse: false)
"アケマシテオメデトウゴザイマス".applyingTransform(.fullwidthToHalfwidth, reverse: true)

※以下の内容はSwift2時点のものです。

文章中の"数字"や、ユーザーの入力した文字列中の "数字"で、もし 全角だったら半角に変換をしたかったので、
まとめてみました。

実装

全角→半角になるものとしては、

  • 全角数字(0, 1, ..., 9)
  • 全角英数字(A, B, C, ...)
  • 全角カタカナ (ア, イ, ウ, エ, オ, ...)
  • その他全角/半角で記号が用意されているもの(ハイフンとか)

があるので、正規表現だけだとちょっと大変です。
そこで、 CoreFoundationで提供されている、 CFStringTransform()
を使います。

CFStringTransformの定義
public func CFStringTransform(string: CFMutableString!, _ range: UnsafeMutablePointer<CFRange>, _ transform: CFString!, _ reverse: Bool) -> Bool
  • 第1引数には CFMutableStringを渡します。
    Swiftの場合、 Stringから直接 CFMutableStringに変換するのは大変なので、 NSMutableStringを経由してCFMutableStringに変換します。

  • 第2引数には、rangeを渡しますが、文字列全てを対象にするなら nilで大丈夫です。

  • 第3引数には、変換をかけるタイプを指定します。今回は全角/半角変換をしたいので、 kCFStringTransformFullwidthHalfwidthを指定します。

  • 第4引数には、かける変換を逆変換にするかどうかを指定します。今回の場合、 kCFStringTransformFullwidthHalfwidthを指定するので、

    • falseを渡せばタイプの名前通り、全角から半角に変換します
    • trueを渡せば逆、つまり半角から全角に変換します。

これをふまえて、以下のように実装をします。

extension String {
    private func convertFullWidthToHalfWidth(reverse: Bool) -> String {
        let str = NSMutableString(string: self) as CFMutableString
        CFStringTransform(str, nil, kCFStringTransformFullwidthHalfwidth, reverse)
        return str as String
    }

    var hankaku: String {
        return convertFullWidthToHalfWidth(reverse: false)
    }

    var zenkaku: String {
        return convertFullWidthToHalfWidth(reverse: true)
    }
}

変換してみる

使用例と変換結果は以下のようになります。

print("000".hankaku) // 000
print("000".zenkaku)   // 000
print("アアア".hankaku) // アアア 
print("AAA".hankaku) // AAA
print("AAA".zenkaku)   // AAA
print("あああ".hankaku) // あああ (そのまま)
print("000".hankaku)   // 000 (半角のものはそのまま)

数字だけ半角/全角変換をしたい

上記のままだと、たとえば、

000 : あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。

という文章に対して、数字だけ半角にしたいと思い半角への変換を実行すると...

let text = "000 : あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。"

print(text.hankaku)
// -> 000 : あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。

と、数字以外のカタカナ、濁点等も半角になってしまいます。 数字だけ変換したい場合は、正規表現で文章中から半角或いは全角数字を抽出して、全角/半角の変換を行う必要があります。

なので、以下のように追記してみます。

extension String {
    // 前略

    private func convertFullWidthToHalfWidthOnlyNumber(fullWidth: Bool) -> String {
        var str = self
        let pattern = fullWidth ? "[0-9]+" : "[0-9]+"
        let regex = try! NSRegularExpression(pattern: pattern, options: [])
        let results = regex.matchesInString(str, options: [], range: NSMakeRange(0, str.characters.count))

        results.reverse().forEach {
            let subStr = (str as NSString).substringWithRange($0.range)
            str = str.stringByReplacingOccurrencesOfString(
                subStr,
                withString: (fullWidth ? subStr.zenkaku : subStr.hankaku))
        }
        return str
    }
    var hankakuOnlyNumber: String {
        return convertFullWidthToHalfWidthOnlyNumber(false)
    }

    var zenkakuOnlyNumber: String {
        return convertFullWidthToHalfWidthOnlyNumber(true)
    }
}

これで、 hankakuOnlyNumberzenkakuOnlyNumberが使えるようになるので、

let text = "000 : あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。"

print(text.hankakuOnlyNumber)
// -> 000 : あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。。

無事、文章中の数字だけ半角に出来ました。
逆に zenkakuOnlyNumberを使えば、

let text2 = "000 : あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。"
print(text2.zenkakuOnlyNumber)
// -> 000 : あのイーハトーヴォのすきとおった風、夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたモリーオ市、郊外のぎらぎらひかる草の波。

と、数字だけ全角にできます。

コード全文

こちらにおいておきます。

おまけ

他にも、ひらがな/カタカナ変換なども用意されているので、同じようにやってみれば、与えた文字列に対して変換をかけられます。
計算型プロパティの名前悩んだのですが、英語でfullWidthとかにするよりはzenkakuのがわかりやすいかなと思ったのでそうしましたが、気に入らなければ英語に直してください〜。

43
39
2

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
43
39