MatchCollection을 string 형 배열로 변환


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;
}

추신 : mc.CopyTo(strArray,0)예외가 발생합니다.

소스 배열에서 하나 이상의 요소를 대상 배열 유형으로 캐스트 할 수 없습니다.

답변:


168

시험:

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

1
OfType<Match>()대신에 이것을 사용했을 것입니다 Cast<Match>()... 그러면 결과는 동일합니다.
Alex

4
@Alex 반환 된 모든 항목이 Match이므로 런타임에 다시 확인할 필요가 없습니다. Cast더 의미가 있습니다.
Servy 2015

2
@DaveBish 아래에 일종의 벤치마킹 코드를 게시했는데 OfType<>약간 더 빠릅니다.
Alex

1
@Frontenderman - 아니, 나는 그냥 askers 질문으로 정렬 한
데이브 Bish

1
당신은이를 설정하는 간단한 명령이 될 것입니다 생각 MatchCollectionstring[]그것을 위해 한, Match.ToString(). 많은 Regex사용에 필요한 최종 유형 은 문자열이 될 것이기 때문에 변환하기 쉬웠어야합니다.
n00dles

32

Dave Bish의 대답은 훌륭하고 제대로 작동합니다.

그것의 가치에 주목하지만 대체 그 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 <>가 느린 이유에 대한 아이디어가 있습니까? 난 아무것도 없어!
Dave Bish 2012

솔직히 단서를 가지고 있지 않지만, 그것은 바로 나에게 "느낌"(OfType은 <> 필터 만, 캐스팅 <>은 ... 음, 캐스트입니다)
알렉스

더 많은 벤치 마크에서이 특정 결과가 사용 된 특정 linq 확장보다 더 많은 정규식으로 인한 것임을 보여줍니다
Alex

6

나는 Alex가 게시 한 것과 똑같은 벤치 마크를 실행했고 때로는 Cast더 빠르고 때로는 OfType더 빠르지 만 둘의 차이는 무시할 만했습니다. 그러나 추악하지만 for 루프는 다른 두 루프보다 지속적으로 빠릅니다.

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는 어떤 사람들에게는 쓰기가 더 쉬우 며 실행 시간을 희생하여 생산성을 "증가"시킬 수 있습니다. 가끔 할 수 있습니다 좋은
gg89

1
따라서 원본 게시물이 실제로 가장 효율적인 방법입니다.
n00dles

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
으 ... 그 정규식은보기에 끔찍합니다. BTW, 이메일 유효성 검사를위한 완벽한 정규식이 없기 때문에 MailAddress 개체를 사용합니다. stackoverflow.com/a/201378/2437521
C. Tewalt
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.