72456


Swiftで、以下のような文字列から、特定の文字列を削除したいと考えています。

以下の3例では、どの場合でも、"test=0|"のように、"test"から始まり、"|"で終わる部分が含まれています。

**・Sample1**  
削除前:`"|5=11|test=0|3=10|30=6|20=2|25=2|1=-11.804115|"`  
削除後:`"|5=11|3=10|30=6|20=2|25=2|1=-11.804115|"`

**・Sample2**  
削除前:`"|4=21|1=14|30=6|27=40|test=25|2=-15.334125|"`  
削除後:`"|4=21|1=14|30=6|27=40|2=-15.334125|"`

**・Sample3**  
削除前:`"|8=33|5=10|32=2|22=1|3=-40.224115|test=100|"`  
削除後:`"|8=33|5=10|32=2|22=1|3=-40.224115|"`

これを、正規表現などを使ってなるべくスマートな方法で除去したいのですが、どうしたら良いでしょうか？  
以下のようなコードでもできなくはないですが、もっとスマートな方法があったら知りたいです。

[code]

    import Foundation
    let testString = "|8=33|5=10|32=2|22=1|3=-40.224115|test=100|"
    let testStringArray = testString.components(separatedBy: "|")
    var testStringArrayReplace:[String] = []
    for test in testStringArray
    {
        if !test.contains("test")
        {
            testStringArrayReplace.append(test)
        }
    }
    print(testStringArrayReplace.compactMap({ $0 }).joined(separator: "|"))
    
[/code]


CC BY-SA 4.0
2020-12-06T10:52:45.707
72454
2020-12-06T11:40:26.690
2020-12-06T11:36:14.500
3060
36446
question
swift 正規表現
Swiftで正規表現、特定の文字列から特定の文字列(最初にヒットした要素)までを削除する方法


「もっとスマートな方法」と言われると、「あなたはどんな方法をスマートと思うのですか？」と聞きたくなるのですが、コード例に示されたような「文字列を一度切り分け、処理をしてからまたつなげる」と言う方法は、コードが長くなる上に実行速度の点でもメモリ消費量の点でも良いことはないので、「正規表現など」をきちんと調べてみられた方が良いでしょう。

「正規表現 オンライン」「regex
online」なんかで検索すると、正規表現のマッチする範囲をオンラインで視覚的にテストできるサイトがすぐにみつかるので、正規表現の入門記事と併用すれば以下に示すような簡単な正規表現はすぐに身につけられると思います。

* * *

Swiftで、正規表現なんかにマッチする部分を削除するにも色々やり方があるのですが、簡単には、以下のような構文(`StringProtocol`型の拡張メソッド)を使うことが多いです。

[code]

    let 結果文字列 = 元の文字列.replacingOccurrences(
            of: 正規表現パターンを表す文字列,
            with: "",
            options: .regularExpression)
    
[/code]

あなたの例で言うと`test=`で始まって`|`で終わる、その間はどんな文字がきても良い(*1)ので、正規表現としてのパターンは、`test=.*\|`になります。正規表現では`.`が「どんな文字でも良い」、`*`が「0回以上の繰り返し」を表しています。`|`は正規表現では特殊な意味を持つので、正規表現のエスケープ文字`\`を付けてあります。

(*1)の部分、実はどんな文字が来ても良い訳じゃないと言うのに気がついてください。

これをSample1の文字列に適用すると、`test=`から最後の`|`まで`test=0|3=10|30=6|20=2|25=2|1=-11.804115|`がごっそりと削除されて、結果が`|5=11|`になってしまいます。

* * *

これを避けるには最小化マッチの`*?`を使う方法なんかもあるんですが、ここでは`.`(どんな文字でも良い)を`[^|]`(`|`以外の文字)に置き換えてみます。

[code]

    let testStrings = [
        "|5=11|test=0|3=10|30=6|20=2|25=2|1=-11.804115|",
        "|4=21|1=14|30=6|27=40|test=25|2=-15.334125|",
        "|8=33|5=10|32=2|22=1|3=-40.224115|test=100|"
    ]
    
    for (index, testString) in testStrings.enumerated() {
        print("・Sample\(index+1)")
        print("削除前:", testString.debugDescription)
        let removedString = testString.replacingOccurrences(
            of: #"test=[^|]*\|"#,
            with: "",
            options: .regularExpression)
        print("削除後:", removedString.debugDescription)
        print()
    }
    
[/code]

文字列の表記に`#"..."#`を使っているのは、「正規表現のエスケープ文字`\`」をSwiftの文字列中に埋め込むために必要な「Swift文字列のエスケープ文字`\`」を省略するためです。普通に書いても`"test=[^|]*\\|"`になるだけですが、正規表現をどんどん使うようになると`\`がやたらとでてくるようになるので、こう書くことがよくあります。

出力

[code]

    ・Sample1
    削除前: "|5=11|test=0|3=10|30=6|20=2|25=2|1=-11.804115|"
    削除後: "|5=11|3=10|30=6|20=2|25=2|1=-11.804115|"
    
    ・Sample2
    削除前: "|4=21|1=14|30=6|27=40|test=25|2=-15.334125|"
    削除後: "|4=21|1=14|30=6|27=40|2=-15.334125|"
    
    ・Sample3
    削除前: "|8=33|5=10|32=2|22=1|3=-40.224115|test=100|"
    削除後: "|8=33|5=10|32=2|22=1|3=-40.224115|"
    
    
[/code]

もう少し色々な例について試してみると、微調整が必要になってくることもありますが、是非ご自身で色々試してみてください。


CC BY-SA 4.0
2020-12-06T11:40:26.690
72456
2020-12-06T11:40:26.690
13972
72454
answer