Swift3.0で文字列操作

Swift3.0で文字列操作

f:id:moapp:20160601182612p:plain

Swiftでは文字列周りの操作はFoundationのライブラリを使うことで簡単に操作することができます。

ですが今回はあえてFoundationを使わないで文字列の操作を一通り行うコードを乗せつつ説明していきます。

文字列同士を結合する

文字列の結合は単純に「+演算子を繋げるだけです。

"123" + "456" // -> "123456"

対象の文字列の配列から1つの文字列に集約する

文字列を配列から集約する場合はjoined(separator: String)関数を使用します。

["1", "2", "3", "4", "5", "6"].joined(separator: "") // -> "123456"

対象の文字列から指定の1文字の位置を検索する

対象の文字列をCharacterの配列として扱い、enumeratedで文字とインデックスを取るようにしておきます。

そして指定の1文字でfilterをかけて、最初にヒットしたインデックスの値を元にString.Indexの値として取得します。

この例では取得したString.Indexの値が取れてることを確認するためにsubscriptでアクセスできるかどうかを確認しています。

extension String {
    
    func index(character: Character) -> String.Index? {
        let index = self.characters.enumerated().filter { (idx, c) in c == character }.first?.0
        guard let offset = index else {
            return nil
        }
        return self.index(self.startIndex, offsetBy: offset)
    }
}

let string = "123456"
if let index = string.index(character: "3") {
    string[index] // -> "3"
}

対象の文字列から指定の文字列の範囲を検索する

対象の文字列が指定の文字列の先頭1文字を含んでいた場合に、一致したインデックスから指定の文字列の長さの数だけ終端のインデックスを取得しておきます。

先頭から終端のインデックスを元にRangeを用意して対象の文字列をスライスし指定の文字列と同じかどうかを比較します。

同じだった場合のみRangeを返します。

extension String {

    func range(string: String) -> Range<String.Index>? {
        guard let startIndex = self.index(character: string[string.startIndex]) else {
            return nil
        }
        
        guard let endIndex = self.index(startIndex, offsetBy: string.characters.count, limitedBy: self.endIndex) else {
            return nil
        }
        
        let range = startIndex..<endIndex
        if self[range] != string {
            return nil
        }
        
        return range
    }
}

let string = "123456"
if let range = string.range(string: "34") {
    string[range] // -> "34"
}

指定する1文字ごとに対象の文字列を分割する

対象の文字列をCharacterの配列として扱い、split(separator: String)関数を利用して分割しています。

extension String {

    func separatedComponents(separator: Character) -> [String] {
        return self.characters.split(separator: separator).map(String.init)
    }
}

"1,2,3,4,5,6".separatedComponents(separator: ",") 
// -> ["1", "2", "3", "4", "5", "6"]

指定する1文字を対象の文字列から取り除く

対象の文字列をCharacterの配列として扱い、指定する1文字でfilterをかけてもう一度文字列として集約をかけます。

extension String {
    
    func removed(character: Character) -> String {
        return self.characters.filter { $0 != character }.map { String($0) }.joined(separator: "")
    }
}

"1,2,3,4,5,6".removed(character: ",") // -> "123456"

指定する文字列を対象の文字列から取り除く

replaceSubrange(range: Range<String.Index>, with: String)を内部で再帰的に呼び出して文字列を取り除きます。

extension String {
    
    func removed(string: String) -> String {
        if let range = self.range(string: string) {
            var mutatingSelf = self
            mutatingSelf.replaceSubrange(range, with: "")
            return mutatingSelf.removed(string: string)
        }
        return self
    }
}

"1, 2, 3, 4, 5, 6".removed(string: ", ") // -> "123456"