2009-03-24 22 views
1

私はfolllowing regexを書いていて空の文字列を自動的に取り除きたいと思いますし、文字列のSplitメソッドだけで見つかったRegexのRemoveEmptyEntriesと等価なものは見つかりませんでした。空の文字列を削除する

string test = "{ key1 = { key2= xx } | key3 = y | key4 = z }"; 
string[] help = Regex.Split(test, "(=)|({)|(})|(\\|)"); 

結果の文字列配列には、空の要素が含まれています。結果に含まれる空の文字列を生成せずに正規表現を実行したいと思います。

私は非常に頻繁にこのコードを実行します - したがって私はできるだけ効率的にそれを必要とします。 アップデート:これはパーサーであるため、トークンを保持する必要があり、Regexでそれらを保持する方法しか見つけられませんでした。

+0

申し訳ありませんが、あなたは「空の文字列が自動的に削除得るために」とは何を意味するのですか?スペースを削除したいですか?それはあまり明確ではない(少なくとも私のために) – Alekc

+0

それは私にも分かりません。どのような入力を示し、どのような出力を期待しているかを示す前後の文字列を投稿できますか? –

+0

結果の文字列配列に空の要素が含まれています。結果に含まれる空の文字列を生成せずに正規表現を実行したいと思います。 – weismat

答えて

2

ない質問への完全なソリューションが、私は当面の問題のため、いくつかの発言(文字列をトークン化)があります。

the original regex: (=)|({)|(})|(\|) 
is equivalent to:  (=|{|}|\|) 
is equivalent to:  ([={}|]) 

を上記の式のすべてが同じ21個の要素を返しますが、彼ら異なって実行する。RegexOptions.CompiledStopwatchクラスの既成のRegexオブジェクトを使用して、Split()の操作を10万回以上繰り返す簡単なテストを設定しました。

  • 正規表現#1私のハードウェア上で2002msを取る
  • 正規表現#2は1691ms
  • 正規表現#3をとる正規表現#4
  • 1542msを取る

(すなわち、以下一つだ)1839msを取りますYMMV。

しかし、希望の要素はまだ空白で囲むことができます。私は、これは同様に望ましくない把握、私は上の分割う正規表現は、このようになります:返される要素がある

\s*([={}|])\s* 

["", "{", "key1", "=", "", "{", "key2", "=", "xx", "}", "", "|", "key3", "=", "y", "|", "key4", "=", "z", "}", ""] 

少数の残りの空の文字列が大きな問題のパフォーマンスを提起するべきではありません配列を反復処理しているときに発生します(読み込み:無視されます)。

EDIT:パフォーマンスを測定すると、([={}|])で分割され、配列要素を「手動で」トリミングすると、\s*([={}|])\s*で分割するよりも高速になる可能性があります。ちょうどあなたのために良い作品を試してみてください。

+0

upvoteが完了しました –

+0

追加の注意:分割後も空の文字列が4つあると考えると、おそらく私の.Where()コードがそれらをフィルタリングする最良の方法でしょう。 –

+0

最初の正規表現でも21個の要素が得られますが、StopWatchを使用してパフォーマンスを測定すると、1000回の反復で4ミリ秒になります。私はあなたの最後の提案を理解していませんでした - あなたは私に正確なコードを教えてください - 悪いエスケープシーケンスを取得します。 – weismat

0

私はあなたの質問をよく理解していませんでした。しかし、 "^ $"は、開始位置の次の行、つまり空行を意味します。それは役に立ちますか?

+0

彼はStringSplitOptions.RemoveEmptyEntriesに相当するhte正規表現を探していると思います。 –

+0

これは私が最初の行で言おうとしたことです - 申し訳ありませんが、私は母国語の母国語ではありません。 – weismat

+0

いいえ問題はありません。 –

4

私はオプションがRegExに組み込まれているとは思わない。しかし、C#3.0で、あなただけのシンプルな.Where()を使用することができます。

string[] help = Regex.Split(test, "(=)|({)|(})|(\\|)") 
        .Where(s => !string.IsNullOrEmpty(s)).ToArray(); 

、これをより効率的にクラスレベルで、おそらく一度—正規表現を宣言するか、それが—静的ではなく、それをすべての時間を再作成するようにするには。さらに、返された配列だけを使用して結果を反復処理している可能性があります。 .ToArray()呼び出しを最後までスキップして、反復処理のためにIEnumerableを保持するだけで、これを高速化できます。

//earlier 
RegEx KeySplitter = new RegEx ("(=)|({)|(})|(\\|)"); 

。 LINQツーオブジェクトがどのように機能するかについての素晴らしい事の

//later 
string test = ""; // 
for (string key in KeySplitter.Split(test).Where(s => !string.IsNullOrEmpty(s))) 
{ 
    // ... 
} 

一つはWhere機能でGetEnumerator方法は、遅延評価を行いますので、これはまだだけで、あなたの.Split結果一回を反復することです。 forループの中で何をする必要があるかによって、.Select()呼び出しを追加することで同様の効率を得ることができます。効率に関しては

+0

Ok - これは、解析を行うときに追加のLINQクエリを追加することを意味します。本当にいいとは言えませんが、少なくとも私はドキュメントから何かを逃していません。 – weismat

+0

「(=)|({)|(})|(\ |)」は、最初は「[= {} |]」と言っても非常に複雑な表現ですか?あるいは、私はここで何か根本的なものを逃していますか文字クラス表現はずっと速くなければなりません。 – Tomalak

+0

*文字クラス式がOPの後にある場合、正規表現を完全に避けるためにString.Split(Char [])があります。 – Tomalak

1

:星は幸運な場合は、正規表現をコンパイルして、いくつかのパフォーマンスを得ることができます:

Regex r = new Regex ("<regex goes here>", RegexOptions.Compiled); 
1

文字列からスペースを削除するには、ちょうどこの

Regex exp = new Regex(@"\s+"); 
string test = "{ key1 = { key2= xx } | key3 = y | key4 = z }"; 
string result = test.Replace(exp, string.Empty); 

それとも、可能性を行います次のようにしてください(どちらが速く動作するかはテストしませんでした)

Regex.Replace(test, " ", string.Empty, RegexOptions.Compiled) 

ここでは、Jeff Atwood (ちなみに、StackOverFlowの作成者の1人はsay about compiled regexです)

この後、分割コードを使用してキーを文字列配列に入れることができます。

たぶん
+0

OPにこれは何度も何度も何度も何度も何度も何度も繰り返されることになるので、正しい選択が集められています。 –

+0

ドアを通って運ぶよりもドアを見せておく方が良い! –

+0

私はそれをコンパイルするように変更しますが、問題は空の文字列要素です。前に空白を削除しません。 – weismat

0

正規表現を使用して文字列を分割するのではなく、正規表現を変更して一致コレクションを返すことができます。

string test = "{ key1 = { key2= xx } | key3 = y | key4 = z }"; 

Regex regex = new Regex("[={}|]|[^\\s={}|]{1,}"); 
MatchCollection matches = regex.Matches(test); 

string[] help = new string[matches.Count]; 

for (int index = 0; index < matches.Count; index++) 
{ 
    help[index] = matches[index].Value;     
} 

最終的な配列の空白(空白)要素を除いた正規表現と同じ結果を返します。

+0

コメントをいただきありがとうございます - 私は空の文字列の有無にかかわらず、私のパーサーのベンチマーク時にもこの可能性を試してみます。 – weismat

0

値間の区切り文字が複数回出現するのは、一度だけ一致させるためです。

\s*[{}=|][\s{}=|]* 

これは、この順序で、任意の空白の量は、ある区切り、そして空白さらにデリミタの両方の任意の量と一致する必要があります。 C#の文字列エスケープとコンパイル宣言を追加

Regex regex = new Regex("\\s*[{}=|][\\s{}=|]*"); 
関連する問題