.NET 정규식에서 명명 된 캡처 그룹에 어떻게 액세스합니까?


255

C #에서 명명 된 캡처 그룹을 사용하는 방법을 설명하는 좋은 리소스를 찾는 데 어려움을 겪고 있습니다. 이것은 지금까지 가지고있는 코드입니다.

string page = Encoding.ASCII.GetString(bytePage);
Regex qariRegex = new Regex("<td><a href=\"(?<link>.*?)\">(?<name>.*?)</a></td>");
MatchCollection mc = qariRegex.Matches(page);
CaptureCollection cc = mc[0].Captures;
MessageBox.Show(cc[0].ToString());

그러나 이것은 항상 전체 라인을 보여줍니다.

<td><a href="/path/to/file">Name of File</a></td> 

다양한 웹 사이트에서 찾은 몇 가지 다른 "방법"을 실험했지만 동일한 결과를 계속 얻습니다.

정규식에 지정된 명명 된 캡처 그룹에 어떻게 액세스 할 수 있습니까?


3
역 참조는 (? <link>. *?) 형식이 아닌 (? <link>. *) 형식이어야합니다.
SO 사용자

11
참고 : 명명 된 캡처 그룹을 xml 파일에 저장하려고하면이 그룹 <>이 손상됩니다. (?'link'.*)이 경우 대신 사용할 수 있습니다 . 이 질문과는 전혀 관련이 없지만 Google 검색에서 ".net named capture groups"를 검색 했으므로 다른 사람들도 마찬가지입니다.
rtpHarry

1
좋은 예가있는 StackOverflow 링크 : stackoverflow.com/a/1381163/463206 또한 @rtpHarry는 아니오를 <>깨뜨리지 않습니다. myRegex.GetGroupNames()컬렉션을 XML 요소 이름으로 사용할 수있었습니다 .
radarbob 2016 년

답변:


263

일치 개체의 그룹 모음을 사용하여 캡처 그룹 이름으로 색인을 생성하십시오 (예 :

foreach (Match m in mc){
    MessageBox.Show(m.Groups["link"].Value);
}

10
사용하지 마십시오 var m그가 될 것이기 때문이다, object.
토마스 웰러

111

명명 된 캡처 그룹 문자열을 Groups결과 Match개체 속성의 인덱서에 전달하여 지정 합니다.

다음은 작은 예입니다.

using System;
using System.Text.RegularExpressions;

class Program
{
    static void Main()
    {
        String sample = "hello-world-";
        Regex regex = new Regex("-(?<test>[^-]*)-");

        Match match = regex.Match(sample);

        if (match.Success)
        {
            Console.WriteLine(match.Groups["test"].Value);
        }
    }
}

10

다음 코드 샘플은 사이에 공백 문자가있는 경우에도 패턴과 일치합니다. 즉 :

<td><a href='/path/to/file'>Name of File</a></td>

만큼 잘:

<td> <a      href='/path/to/file' >Name of File</a>  </td>

메소드는 입력 htmlTd 문자열이 패턴과 일치하는지 여부에 따라 true 또는 false를 리턴합니다. 일치하면 출력 매개 변수에 각각 링크와 이름이 포함됩니다.

/// <summary>
/// Assigns proper values to link and name, if the htmlId matches the pattern
/// </summary>
/// <returns>true if success, false otherwise</returns>
public static bool TryGetHrefDetails(string htmlTd, out string link, out string name)
{
    link = null;
    name = null;

    string pattern = "<td>\\s*<a\\s*href\\s*=\\s*(?:\"(?<link>[^\"]*)\"|(?<link>\\S+))\\s*>(?<name>.*)\\s*</a>\\s*</td>";

    if (Regex.IsMatch(htmlTd, pattern))
    {
        Regex r = new Regex(pattern,  RegexOptions.IgnoreCase | RegexOptions.Compiled);
        link = r.Match(htmlTd).Result("${link}");
        name = r.Match(htmlTd).Result("${name}");
        return true;
    }
    else
        return false;
}

나는 이것을 테스트했으며 올바르게 작동합니다.


1
중괄호가 그룹에 액세스 할 수 있음을 상기시켜 주셔서 감사합니다. 나는 ${1}일을 더 단순하게 유지 하는 것을 선호합니다 .
Magnus Smith

이것은 완전히 질문에 대한 대답, 그러나 여기에서 설명하는 데 시간이 너무 오래 몇 가지 문제가있다,하지만 난에 그 설명 및 수정 내 대답은 아래
마리아노 Desanze

1

또한 누군가 Regex 객체에서 검색을 실행하기 전에 그룹 이름이 필요한 유스 케이스가있는 경우 다음을 사용할 수 있습니다.

var regex = new Regex(pattern); // initialized somewhere
// ...
var groupNames = regex.GetGroupNames();

1

이 답변은 Rashmi Pandit의 답변 에서 개선됩니다.이 답변은 질문에 자세히 설명 된 정확한 문제를 완전히 해결하는 것이므로 나머지 것보다 낫습니다.

나쁜 점은 비효율적이며 IgnoreCase 옵션을 지속적으로 사용하지 않는다는 것입니다.

비효율적 인 부분은 정규 표현식이 구성하고 실행하는 데 비용이 많이들 수 있기 때문에 그 대답에서 한 번만 구성 할 수 있었기 때문입니다 (호출 Regex.IsMatch은 무대 뒤에서 정규 표현식을 다시 구성하는 것입니다). 그리고 Match방법은 한 번만 호출하고 변수에 저장하고 있었을 linkname호출해야 Result하는 변수에서.

그리고 IgnoreCase 옵션은 Match파트 에서만 사용 되었지만 파트에서는 ​​사용되지 않았습니다 Regex.IsMatch.

또한 한 번만 구성하기 위해 메소드 외부에서 Regex 정의를 옮겼습니다 ( RegexOptions.Compiled옵션으로 해당 어셈블리를 저장하는 경우 합리적인 접근법이라고 생각합니다 ).

private static Regex hrefRegex = new Regex("<td>\\s*<a\\s*href\\s*=\\s*(?:\"(?<link>[^\"]*)\"|(?<link>\\S+))\\s*>(?<name>.*)\\s*</a>\\s*</td>",  RegexOptions.IgnoreCase | RegexOptions.Compiled);

public static bool TryGetHrefDetails(string htmlTd, out string link, out string name)
{
    var matches = hrefRegex.Match(htmlTd);
    if (matches.Success)
    {
        link = matches.Result("${link}");
        name = matches.Result("${name}");
        return true;
    }
    else
    {
        link = null;
        name = null;
        return false;
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.