MatchCollectionを文字列配列に変換する


83

これよりもMatchCollectionを文字列配列に変換するためのより良い方法はありますか?

MatchCollection mc = Regex.Matches(strText, @"\b[A-Za-z-']+\b");
string[] strArray = new string[mc.Count];
for (int i = 0; i < mc.Count;i++ )
{
    strArray[i] = mc[i].Groups[0].Value;
}

PS:mc.CopyTo(strArray,0)例外をスローします:

ソース配列の少なくとも1つの要素を、宛先配列タイプにキャストできませんでした。

回答:


168

試してみてください:

var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
    .Cast<Match>()
    .Select(m => m.Value)
    .ToArray();

1
私はOfType<Match>()代わりにこれを使用したでしょうCast<Match>()...そしてまた、結果は同じでしょう。
アレックス

4
@Alex返されるものはすべてであることがわかっているMatchので、実行時に再度チェックする必要はありません。 Castより理にかなっています。
Servy 2012

2
@DaveBishある種のベンチマークコードを以下に投稿OfType<>しましたが、少し速いことがわかりました。
アレックス

1
@ Frontenderman-いいえ、質問者の質問に合わせていました
Dave Bish

1
あなたはそれを有効にする簡単なコマンドと思うだろうMatchCollectionstring[]、それがためであるとして、Match.ToString()。多くのRegex用途で必要とされる最終的な型が文字列であることは明らかなので、変換は簡単だったはずです。
n00dles 2017年

32

デイブビッシュの答えは良く、正しく機能します。

に置き換えるCast<Match>()と処理OfType<Match>()速度が向上しますが、注目に値します。

コードは次のようになります。

var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
    .OfType<Match>()
    .Select(m => m.Groups[0].Value)
    .ToArray();

結果はまったく同じです(そしてOPの問題にまったく同じ方法で対処します)が、巨大な文字列の場合はより高速です。

テストコード:

// put it in a console application
static void Test()
{
    Stopwatch sw = new Stopwatch();
    StringBuilder sb = new StringBuilder();
    string strText = "this will become a very long string after my code has done appending it to the stringbuilder ";

    Enumerable.Range(1, 100000).ToList().ForEach(i => sb.Append(strText));
    strText = sb.ToString();

    sw.Start();
    var arr = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
              .OfType<Match>()
              .Select(m => m.Groups[0].Value)
              .ToArray();
    sw.Stop();

    Console.WriteLine("OfType: " + sw.ElapsedMilliseconds.ToString());
    sw.Reset();

    sw.Start();
    var arr2 = Regex.Matches(strText, @"\b[A-Za-z-']+\b")
              .Cast<Match>()
              .Select(m => m.Groups[0].Value)
              .ToArray();
    sw.Stop();
    Console.WriteLine("Cast: " + sw.ElapsedMilliseconds.ToString());
}

出力は次のとおりです。

OfType: 6540
Cast: 8743

以下のために非常に長い文字列のキャスト()ので遅いです。


1
非常に驚くべき!OfTypeが内部のどこかで「is」比較を実行する必要があることを考えると(私は思っていたでしょう?)Cast <>が遅い理由について何か考えはありますか?何もありません!
デイブビッシュ2012

私には正直なところ手がかりはありませんが、それは私にとって正しいと「感じ」ます(OfType <>は単なるフィルターであり、Cast <>は...まあ、キャストです)
Alex

より多くのベンチマークは、この特定の結果が、使用された特定のlinq拡張機能よりも正規表現によるものであることを示しているようです
Alex

6

Alexが投稿したのとまったく同じベンチマークを実行したところ、Cast速い場合と速い場合がありましたOfTypeが、両者の違いはごくわずかでした。ただし、醜いですが、forループは他の2つよりも一貫して高速です。

Stopwatch sw = new Stopwatch();
StringBuilder sb = new StringBuilder();
string strText = "this will become a very long string after my code has done appending it to the stringbuilder ";
Enumerable.Range(1, 100000).ToList().ForEach(i => sb.Append(strText));
strText = sb.ToString();

//First two benchmarks

sw.Start();
MatchCollection mc = Regex.Matches(strText, @"\b[A-Za-z-']+\b");
var matches = new string[mc.Count];
for (int i = 0; i < matches.Length; i++)
{
    matches[i] = mc[i].ToString();
}
sw.Stop();

結果:

OfType: 3462
Cast: 3499
For: 2650

linqがforループよりも遅いのは当然のことです。Linqは、一部の人にとっては書きやすく、実行時間を犠牲にして生産性を「向上」させる可能性があります。それは時々良い
かもしれ

1
したがって、元の投稿が実際に最も効率的な方法です。
n00dles 2017年

2

この拡張方法を利用して、MatchCollection一般的でないという煩わしさに対処することもできます。それは大したことではありませんが、これはほぼ確実に、OfTypeまたはよりもパフォーマンスが高くCastなります。これは、列挙しているだけなので、どちらも実行する必要があります。

(サイドノート:それは作るために.NETチームのために可能である場合、私は疑問に思うMatchCollectionの継承ジェネリックICollectionIEnumerable?将来的にはその後、我々はすぐにLINQが使用可能に変換するには、この余分なステップを必要としません)。

public static IEnumerable<Match> ToEnumerable(this MatchCollection mc)
{
    if (mc != null) {
        foreach (Match m in mc)
            yield return m;
    }
}

0

次のコードを検討してください...

var emailAddress = "joe@sad.com; joe@happy.com; joe@elated.com";
List<string> emails = new List<string>();
emails = Regex.Matches(emailAddress, @"([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})")
                .Cast<Match>()
                .Select(m => m.Groups[0].Value)
                .ToList();

1
うーん...その正規表現は見るのが恐ろしいです。ところで、電子メールを検証するための絶対確実な正規表現は存在しないため、MailAddressオブジェクトを使用してください。stackoverflow.com/a/201378/2437521
C. Tewalt 2014
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.