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

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

```swift
"アケマシテオメデトウゴザイマス".applyingTransform(.fullwidthToHalfwidth, reverse: false)
"ｱｹﾏｼﾃｵﾒﾃﾞﾄｳｺﾞｻﾞｲﾏｽ".applyingTransform(.fullwidthToHalfwidth, reverse: true)
```

- [applyingTransform(_:reverse:) - String | Apple Developer Documentation](https://developer.apple.com/reference/swift/string/1643133-applyingtransform)

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


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

## 実装

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

- 全角数字(０, １, ..., ９)
- 全角英数字(Ａ, Ｂ, Ｃ, ...)
- 全角カタカナ (ア, イ, ウ, エ, オ, ...)
- その他全角/半角で記号が用意されているもの（ハイフンとか）

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

```swift: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**を渡せば逆、つまり半角から全角に変換します。

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


```swift
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)
    }
}
```

## 変換してみる

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

```swift
print("０００".hankaku) // 000
print("000".zenkaku)   // ０００
print("アアア".hankaku) // ｱｱｱ 
print("ＡＡＡ".hankaku) // AAA
print("AAA".zenkaku)   // ＡＡＡ
print("あああ".hankaku) // あああ (そのまま)
print("000".hankaku)   // 000 (半角のものはそのまま)
```


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

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

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

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

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

print(text.hankaku)
// -> 000 : あのｲｰﾊﾄｰｳﾞｫのすきとおった風､夏でも底に冷たさをもつ青いそら､うつくしい森で飾られたﾓﾘｰｵ市､郊外のぎらぎらひかる草の波｡
```

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

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

```swift
extension String {
    // 前略
    
    private func convertFullWidthToHalfWidthOnlyNumber(fullWidth: Bool) -> String {
        var str = self
        let pattern = fullWidth ? "[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)
    }
}
```

これで、 **`hankakuOnlyNumber`**と **`zenkakuOnlyNumber`**が使えるようになるので、

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

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

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

```swift
let text2 = "000 : あのｲｰﾊﾄｰｳﾞｫのすきとおった風､夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたﾓﾘｰｵ市、郊外のぎらぎらひかる草の波。"
print(text2.zenkakuOnlyNumber)
// -> ０００ : あのｲｰﾊﾄｰｳﾞｫのすきとおった風､夏でも底に冷たさをもつ青いそら、うつくしい森で飾られたﾓﾘｰｵ市、郊外のぎらぎらひかる草の波。
```

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

## コード全文

[こちら](https://gist.github.com/sgr-ksmt/2dcf11a64cdb22d44517)においておきます。

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