Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails以外の開発一般

Swiftでの文字列置換について

BPSの福岡拠点として一緒にお仕事をさせていただいています、株式会社ウイングドアの岡です。

今回、Swiftでの文字列置換についてご紹介したいと思います。

文字列内でマッチした部分文字列が、正しく置換できるようになることを
目的にやっていきたいと思います。

Swiftで文字列置換させようとしている方へ少しだけでも、
アドバイスになれば、うれしいです。

今回使用したバーションはSwift 5になります。

Rubyでの文字列置換

はじめに、Rubyでの文字列置換を見ていきましょう。
subメソッドを使った方法とgsubメソッドになります。

irb(main):022:0> irb(main):023:0> hogehoge = "ああいうああえお"
=> "ああいうああえお"  
irb(main):026:0> hogehoge.sub("ああ","あか")
=> "あかいうああえお"  

subメソッドはマッチした最初の文字のみを置き換えた状態で文字列を生成して返します。

irb(main):005:0> hogehoge = "ああいうああえお"  
=> "ああいうああえお"  
irb(main):006:0> hogehoge.gsub("ああ","あか")  
=> "あかいうあかえお"  

gsubメソッドはマッチする部分全てを置き換えた状態で文字列を生成して返します。

Swiftでの文字列置換

replaceSubrangeでの方法

後々、何かと便利なのでStringを拡張して実装してみました。

まず、rangeメソッドで文字列中に置換したい文字があるかを
検索し文字列が見つかった場合は、Range型で一致した文字位置が返ってくるので
replaceSubrangeメソッドで返ってきた文字位置に置換後の文字を入れ替えてます。

破壊的メソッドなので使用には注意して使う必要があるかと思います。

extension String {
    func replace(_ from: String,_ to: String) -> String {
        var replacedString = self
        if let range = replacedString.range(of: from) {
            replacedString.replaceSubrange(range, with: to)
        }
        return replacedString
    }
}

では、実際に確認してみましょう。

var hogehoge = "ああいうああえお"  
print(hogehoge.replace("ああ","あか"))  
>  あかいうああえお  

置換自体はできてますが、ヒットした文字の最初だけしか、置換されてないようです。
ヒットした文字が、全て置換されるようにする必要がありますね。

複数の文字を置換できるように変更後

extension String {
    func replace(_ from: String,_ to: String) -> String {
        var replacedString = self

        while((replacedString.range(of: from)) != nil){
            if let range = replacedString.range(of: from) {
                replacedString.replaceSubrange(range, with: to)
            }
        }

        return replacedString
    }
}

ループさせ置換対象の文字がヒットされるまで繰り返すよう変更してみました。
ヒットした文字が、全て置換されるか試してみましょう。

var hogehoge = "ああいうああえお"

print(hogehoge.replace("ああ","あか"))
> あかいうあかえお

ちゃんと置換されてますね。と思ったのですが、
文字列の置換中にrangeでの検索で無限にヒットしている場合が判明。

var hogehoge = "あいうえお"

print(hogehoge.replace("あ", "あか"))
print(hogehoge.replace("あ", "あ"))
> 無限ループしてしまう

これだとダメなので別の方法で解決する必要がありますね。

replacingOccurrencesでの実装

公式ドキュメントを調べていくとreplacingOccurrencesというメソッドでも置換できるという
ことが分かり試しに実装してみました。

同じようにStringを拡張して使いやすいようにしてみました。
replacingOccurrencesは非破壊的メソッドになります。

extension String {
    func replace(_ from: String,_ to: String) -> String {
        var replacedString = self
        replacedString = replacedString.replacingOccurrences(of: from, with: to)

        return replacedString
    }
}

試してみましょう。

var hogehoge = "ああいうああえお"
print(hogehoge.replace("ああ","あか"))
> あかいうあかえお

var hogehoge = "あいうえお"

print(hogehoge.replace("あ", "あか"))
print(hogehoge.replace("あ", "あ"))  
> あかいうえお
> あいうえお

目的通り、複数文字列が置換され、同じ文字があっても正しく置換されました。

まとめ

Swiftを使った文字列置換について紹介しました。
今回は、replacingOccurrencesを使い解決しましたが
用途ごとに、分けて使う必要があるかと思いました。

参考に、公式ドキュメントを貼っておきましたので
使用する際は確認して使ってみてください。


株式会社ウイングドアでは、Ruby on RailsやPHPを活用したwebサービス、webサイト制作を中心に、
スマホアプリや業務系システムなど様々なシステム開発を承っています。


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。