web-dev-qa-db-ja.com

文字列内の区切り文字を削除します(正規表現を使用しますか?)

一致する文字セットのペアを検索し、それらの間の文字およびそれらの文字/区切り文字を削除する要件を考慮してください。

区切り文字のセットは次のとおりです。

 []    square brackets
 ()    parentheses
 ""    double quotes
 ''    single quotes

一致する必要がある文字列の例を次に示します。

 Given:                       Results In:
-------------------------------------------
 Hello "some" World           Hello World
 Give [Me Some] Purple        Give Purple
 Have Fifteen (Lunch Today)   Have Fifteen
 Have 'a good'day             Have day

そして、一致してはならない文字列の例:

 Does Not Match:
------------------
 Hello "world
 Brown]co[w
 Cheese'factory

指定された文字列に一致する区切り文字のセットが含まれていない場合、変更されません。入力文字列には、多くの一致する区切り文字のペアが含まれる場合があります。 2つの区切り文字のセットが重複している場合(つまり、he[llo "worl]d")、それはここで無視できるEdgeケースです。

アルゴリズムは次のようになります。

string myInput = "Give [Me Some] Purple (And More) Elephants";
string pattern; //some pattern
string output = Regex.Replace(myInput, pattern, string.Empty);

質問: C#でこれをどのように実現しますか?私は正規表現に傾いています。

ボーナス:これらの開始および終了区切り文字を定数またはある種のリストに一致させる簡単な方法はありますか?私が探している解決策は、ビジネスアナリストが新しい区切り文字のセットを見つけた場合に、区切り文字を簡単に変更できることです。

44
p.campbell

単純な正規表現は次のとおりです。

string input = "Give [Me Some] Purple (And More) Elephants";
string regex = "(\\[.*\\])|(\".*\")|('.*')|(\\(.*\\))";
string output = Regex.Replace(input, regex, "");

正規表現を構築したいカスタムの方法については、パーツを構築する必要があります:

('.*')  // example of the single quote check

次に、元の例のように、個々の正規表現部分をOR(正規表現の|)で連結します。正規表現文字列を作成したら、一度だけ実行します。 1つのアイテムで多くの正規表現の一致を実行し、多くのアイテムを反復処理すると、パフォーマンスが大幅に低下する可能性があるため、1つのチェックにまとめます。

最初の例では、次の行の代わりになります。

string input = "Give [Me Some] Purple (And More) Elephants";
string regex = "Your built up regex here";
string sOutput = Regex.Replace(input, regex, "");

誰かがクールなlinq式を投稿して、一致するデリミターオブジェクトの配列などに基づいて正規表現を構築すると確信しています。

43
Kelsey

簡単な方法はこれを行うことです:

string RemoveBetween(string s, char begin, char end)
{
    Regex regex = new Regex(string.Format("\\{0}.*?\\{1}", begin, end));
    return regex.Replace(s, string.Empty);
}

string s = "Give [Me Some] Purple (And More) \\Elephants/ and .hats^";
s = RemoveBetween(s, '(', ')');
s = RemoveBetween(s, '[', ']');
s = RemoveBetween(s, '\\', '/');
s = RemoveBetween(s, '.', '^');

Returnステートメントを次のように変更すると、空のスペースが重複しないようになります。

return new Regex(" +").Replace(regex.Replace(s, string.Empty), " ");

最終的な結果は次のようになります。

"Give Purple and "

Disclamer:単一の正規表現はおそらくこれよりも速いでしょう。

35
Bryan Menard

「問題があり、正規表現を使用したいのですが、今は2つの問題があります」という古い格言を追加する必要があります。

私はあなたが探している方向にあなたを助けることができる簡単な正規表現を考え出しました:

[.]*(\(|\[|\"|').*(\]|\)|\"|')[.]*

括弧、角括弧、二重引用符はエスケープされますが、一重引用符はそのままにすることができます。

上記の式を英語にするために、一致する区切り文字の間にある式と一致する前と後の任意の数の文字を許可しています。

オープンデリミタフレーズは(\(|\[|\"|')これには、一致する終了フレーズがあります。将来これをもう少し拡張可能にするために、実際の区切り文字を削除して、構成ファイル、データベース、または任意の場所に含めることができます。

9
Alexis Abril

Bryan Menardの正規表現 に基づいて、「[Test 1 [[Test2] Test3]] Hello World」のようなネストされた置換でも機能する拡張メソッドを作成しました。

    /// <summary>
    /// Method used to remove the characters betweeen certain letters in a string. 
    /// </summary>
    /// <param name="rawString"></param>
    /// <param name="enter"></param>
    /// <param name="exit"></param>
    /// <returns></returns>
    public static string RemoveFragmentsBetween(this string rawString, char enter, char exit) 
    {
        if (rawString.Contains(enter) && rawString.Contains(exit))
        {
            int substringStartIndex = rawString.IndexOf(enter) + 1;
            int substringLength = rawString.LastIndexOf(exit) - substringStartIndex;

            if (substringLength > 0 && substringStartIndex > 0)
            {
                string substring = rawString.Substring(substringStartIndex, substringLength).RemoveFragmentsBetween(enter, exit);
                if (substring.Length != substringLength) // This would mean that letters have been removed
                {
                    rawString = rawString.Remove(substringStartIndex, substringLength).Insert(substringStartIndex, substring).Trim();
                }
            }

            //Source: https://stackoverflow.com/a/1359521/3407324
            Regex regex = new Regex(String.Format("\\{0}.*?\\{1}", enter, exit));
            return new Regex(" +").Replace(regex.Replace(rawString, string.Empty), " ").Trim(); // Removing duplicate and tailing/leading spaces
        }
        else
        {
            return rawString;
        }
    }

提案された場合、このメソッドの使用法は次のようになります。

string testString = "[Test 1 [[Test2] Test3]] Hello World";
testString.RemoveFragmentsBetween('[',']');

文字列「Hello World」を返します。

3

次の正規表現を使用します

(\{\S*\})

この正規表現が行うことは、{Word}の出現を、置換したいmodifiedWordに置き換えます。

いくつかのサンプルC#コード:

 static readonly Regex re = new Regex(@"(\{\S*\})", RegexOptions.Compiled);
        /// <summary>
        /// Pass text and collection of key/value pairs. The text placeholders will be substituted with the collection values.
        /// </summary>
        /// <param name="text">Text that containes placeholders such as {fullname}</param>
        /// <param name="fields">a collection of key values pairs. Pass <code>fullname</code> and the value <code>Sarah</code>. 
        /// DO NOT PASS keys with curly brackets <code>{}</code> in the collection.</param>
        /// <returns>Substituted Text</returns>
        public static string ReplaceMatch(this string text, StringDictionary fields)
        {
            return re.Replace(text, match => fields[match.Groups[1].Value]);
        }

次のような文で

Regex Heroは、リアルタイム{オンライン{Silverlight} Regular} Expression Testerです。

{Silverlight}のみを置き換え、最初の{大括弧から最後の}大括弧までは置き換えません。

0
jaxxbo