|   | |||||
| 対象: 正規表現による文字列の抽出(Swift)正規表現を使って文字列中にある任意のパターンにマッチした部分文字列を抽出する。NSRegularExpressionを使うと、正規表現を用いた文字列のマッチ、及び抽出を行うことができる。 グループ機能にも対応しており、正規表現パターン中の()で括った部分文字列をキャプチャすることもできる。正規表現パターンにおける各グループは、firstMatchメソッドから返されるNSTextCheckingResultオブジェクトのrangeメソッドで取得できる。 検索対象の文字列から、マッチさせたグループ毎に文字列を抽出するためにNSStringのsubstringメソッドを使う。このため、予め検索対象の文字列をNSStringにキャストする等しておくと後で楽かも知れない。 
        // 正規表現を使って文字列を抽出
        // NSRangeを扱うので検索対象の文字列は先にNSStringにしておくと後で楽かも
        let nsSentence: NSString = "Apple?は新しい言語Swiftを発表しました。"
        let regex = try? NSRegularExpression(pattern: "(?i)^(apple.{1})は.*(swift)を(.*)しました。$", options: NSRegularExpression.Options())
        if let result = regex?.firstMatch(in: nsSentence as String, options: NSRegularExpression.MatchingOptions(), range: NSMakeRange(0, nsSentence.length)) {
            // Swift 3の書き方
            // if let range = result.range.toRange() {
            // Swift 4の書き方
            if let range = Range(result.range) {
                print("range: \(range) string: \(nsSentence.substring(with: result.range))")
            }
            print(result.numberOfRanges)
            for i in 0..<result.numberOfRanges {
                // Swift 3の書き方
                // if let range = result.rangeAt(i).toRange() {
                // Swift 4の書き方
                if let range = Range(result.range(at: i)) {
                    // Swift 3の書き方
                    // print("range(\(i)): \(range) string: \(nsSentence.substring(with: result.rangeAt(i)))")
                    // Swift 4の書き方
                    print("range(\(i)): \(range) string: \(nsSentence.substring(with: result.range(at: i)))")
                }
            }
        } else {
            print("文字列は見つかりませんでした。")
        }
以下のように、rangeプロパティ、及びrange(at: 0)で得られる範囲の文字列はマッチした文字列全体、range(at: 1)以降で得られる範囲の文字列は各グループの文字列となる。上記の正規表現パターンで言えば、(apple.{1})はグループ1、(swift)はグループ2、そして(.*)はグループ3となる。 range: 0..<26 string: Apple?は新しい言語Swiftを発表しました。 range(0): 0..<26 string: Apple?は新しい言語Swiftを発表しました。 range(1): 0..<7 string: Apple? range(2): 13..<18 string: Swift range(3): 19..<21 string: 発表 NSRegularExpressionの正規表現パターンで(?i)フラグを使う代わりに、options引数でNSRegularExpression.Options.caseInsensitiveを渡すと、(?i)フラグと同じ効果が得られる。これはケースバイケースなので、好きなほうを使うと良いだろう。もちろん、大文字小文字を区別して(casesensitive)パターンにマッチさせたい場合はどちらも必要ない。 
        // 正規表現パターンで(?i)フラグを使う代わりに、options引数でNSRegularExpression.Options.caseInsensitiveを指定
        let regex = try? NSRegularExpression(pattern: "^(apple.{1})は.*(swift)を(.*)しました。$", options: .caseInsensitive)
グループ機能を使えば、例えば日時を表す文字列から年、月、及び日だけを簡単に取り出すことができる。数字を表す正規表現として\d(バックスラッシュd)が使えるが、Swiftの場合、\(バックスラッシュ)は文字列の補間にも使われているため、\\d(バックスラッシュバックスラッシュd)と2つ重ねてエスケープする必要がある。4ケタの整数であれば(\\d{4})でキャプチャできる。 
        let nsDateStr: NSString = "2015-09-09 08:43:59"
        let rd = try? NSRegularExpression(pattern: "^(\\d{4})-(\\d{2})-(\\d{2})", options: NSRegularExpression.Options())
        if let r = rd?.firstMatch(in: nsDateStr as String, options: NSRegularExpression.MatchingOptions(), range: NSMakeRange(0, nsDateStr.length)) {
            // Swift 3の書き方
            // print("西暦\(nsDateStr.substring(with: r.rangeAt(1)))年\(nsDateStr.substring(with: r.rangeAt(2)))月\(nsDateStr.substring(with: r.rangeAt(3)))日です。")
            // Swift 4の書き方
            print("西暦\(nsDateStr.substring(with: r.range(at: 1)))年\(nsDateStr.substring(with: r.range(at: 2)))月\(nsDateStr.substring(with: r.range(at: 3)))日です。")
        }
西暦2015年09月09日です。 単純にマッチさせたいだけなら、対象の文字列はNSStringでなくただのStringでも良いかも知れない。以下は文字列がiPhone 4s、5、5s、6、または6sの場合にiOS 9に対応していると表示する例である。 \s(バックスラッシュs)は空白文字にマッチする。また、*は0回以上の繰返しを意味するので、"iPhone"と"6s"の間のスペースはあってもなくてもマッチする。(?:)はキャプチャされないグループを意味し、候補の文字列がいくつかある場合に使える。 
        let ios9re = try? NSRegularExpression(pattern: "^(?i)iPhone\\s*(?:4s|5|5s|6|6s)$", options: NSRegularExpression.Options())
        // 単純にマッチさせたいだけならStringで良いかも
        let phones = ["iPhone 4", "iPhone 4s", "iPhone 5", "IPHONE 5S", "iPhone  6", "iphone6s"]
        for phone in phones {
            // NSString.lengthはString.utf16.countで代用できそう
            if let _ = ios9re?.firstMatch(in: phone, options: NSRegularExpression.MatchingOptions(), range: NSMakeRange(0, phone.utf16.count)) {
                print("\(phone)はiOS 9に対応しています。")
            } else {
                print("\(phone)はiOS 9に対応していません。")
            }
        }
iPhone 4はiOS 9に対応していません。 iPhone 4sはiOS 9に対応しています。 iPhone 5はiOS 9に対応しています。 IPHONE 5SはiOS 9に対応しています。 iPhone 6はiOS 9に対応しています。 iphone6sはiOS 9に対応しています。 正直な印象としてあまり使いやすいとは感じないが、Swiftでもとりあえず正規表現を使用した文字列の検索・抽出が可能となっている。 (2015/02/20) () Swift 4.0対応。 
 Copyright© 2004-2019 モバイル開発系(K) All rights reserved. [Home] | |||||