2012-11-10 5 views
3

RegEx.Matches를 사용하여 일치하는 값을 찾아 다른 순서로 (알파벳순으로) 다시 쓸 수있는 방법이 있습니까?C# 정렬 및 다시 넣기 Regex.matches

var pattern = @"(KEY `[\w]+?` \(`.*`*\))"; 
var keys = Regex.Matches(line, pattern); 

Console.WriteLine("\n\n"); 
foreach (Match match in keys) 
{ 
    Console.WriteLine(match.Index + " = " + match.Value.Replace("\n", "").Trim()); 
} 

하지만 내가 정말 필요로하는 것은 table.sql 덤프 및 알파벳 순으로 정렬 기존 인덱스, 예제 코드 걸릴 것입니다 :

line = "...PRIMARY KEY (`communication_auto`),\n KEY `idx_current` (`current`),\n KEY `idx_communication` (`communication_id`,`current`),\n KEY `idx_volunteer` (`volunteer_id`,`current`),\n KEY `idx_template` (`template_id`,`current`)\n);" 

감사를 J 지금은

내가 좋아하는 뭔가를


업데이트 : 감사합니다. m.buettner 솔루션을 통해 내가 계속 전진 할 수있는 기초를 갖게되었습니다. 나는 슬프게 정규식에 너무 좋은 아니에요,하지만 난 여전히 개선 될 수 있다고 믿는 그 코드와 함께 종료 :

... 
//sort INDEXES definitions alphabetically 
if (line.Contains(" KEY `")) line = Regex.Replace(
    line, 
    @"[ ]+(KEY `[\w]+` \([\w`,]+\),?\s*)+", 
    ReplaceCallbackLinq 
); 

static string ReplaceCallbackLinq(Match match) 
{ 
    var result = String.Join(",\n ", 
     from Capture item in match.Groups[1].Captures 
     orderby item.Value.Trim() 
     select item.Value.Trim().Replace("),", ")") 
    ); 
    return " " + result + "\n"; 
} 


업데이트 : 인덱스 필드가 경우도 있습니다 때 ReplaceCall에 :

KEY `idx3` (`app_property_definition_id`,`value`(255),`audit_current`), 

너무, 너무,이 경우 일치하기 위해 나는 몇 가지 코드를 변경했다 : 255 개 문자보다 긴 MySQL은 255 인덱스를 트림과 같이 씁니다 backLinq :

select item.Value.Trim().Replace("`),", "`)") 

및 정규식 정의 :

foreach (Match match in keys.Cast<Match>().OrderBy(m => m.Value)) 

당신이 원하는 게 무엇을 : 나는 완전히 질문을 이해하지만,에 foreach 문을 변경 않을 경우

@"[ ]+(KEY `[\w]+` \([\w`(\(255\)),]+\),?\s*)+", 

답변

2

정규식으로는이 작업을 수행 할 수 없습니다. 그러나 콜백 함수를 사용하여 동일한 캡처 그룹을 사용하여 여러 가지를 캡처하는 .NET의 고유 한 기능을 사용할 수 있습니다. 이렇게하면 Matches을 사용하지 않고 모든 것을 직접 쓰지 않아도됩니다. 대신 내장 된 Replace 기능을 사용하십시오. 아래의 예제는 단순히 KEY 구를 정렬하고 원래대로 되돌려 놓습니다 (SQL 문 내에서 구를 정렬하기 만합니다). 다른 출력을 원할 경우 패턴의 다른 부분을 캡처하고 맨 마지막에 Join 조작을 조정하여 쉽게 얻을 수 있습니다.

MatchEvaluator evaluator = new MatchEvaluator(ReplaceCallback); 

그런 다음 우리는 캡처 그룹의 인덱스 이름을 캡처 한 번에 인덱스의 전체 집합 일치하는 정규식 쓰기 :

먼저 우리는 콜백을 전달하는 경기 평가가 필요합니다. (1) 항상 캡처 된 첫 번째 또는 마지막 일을 포함하기 때문 인해 반복 캡처 그룹에,

지금
output = Regex.Replace(
    input, 
    @"(KEY `([\w]+)` \(`[^`]*`(?:,`[^`]*`)*\),?\s*)+", 
    evaluator 
); 

은 대부분의 언어에서이 유용하지 않을 것입니다 : 우리는 평가자 소요 Replace의 과부하에 넣고 (포획 그룹 2와 동일).다행히도 C#을 사용하고 .NET의 정규식 엔진은 하나의 강력한 짐승입니다. 그럼 어떻게 여러 캡처를 사용하는 콜백 함수보고를하자 :

static string ReplaceCallback(Match match) 
{ 
    int captureCount = match.Groups[1].Captures.Count; 
    string[] indexNameArray = new string[captureCount]; 
    string[] keyBlockArray = new string[captureCount]; 
    for (int i = 0; i < captureCount; i++) 
    { 
     keyBlockArray[i] = match.Groups[1].Captures[i].Value; 
     indexNameArray[i] = match.Groups[2].Captures[i].Value; 
    } 
    Array.Sort(indexNameArray, keyBlockArray); 
    return String.Join("\n ", keyBlockArray); 
} 

match.Groups[i].Captures 우리가 하나의 그룹의 여러 캡처에 액세스 할 수 있습니다. 이것들은 Capture 객체 들이기 때문에 지금은별로 유용하지 않은 것처럼 보입니다. 우리는 값으로부터 두 개의 문자열 배열을 만듭니다. 그런 다음 Array.Sort을 사용하여 하나의 값 (키로 간주 됨)에 따라 두 개의 배열을 정렬합니다. "키"는 테이블 이름의 캡처를 사용합니다. "가치"로서 우리는 완전한 KEY ..., 블록의 전체 캡처를 사용합니다. 전체 블록을 이름순으로 정렬합니다. 그런 다음 블록을 함께 결합하고 이전에 사용 된 공백 구분 기호를 추가하여이를 반환 할 수 있습니다.

+0

감사합니다.이 솔루션을 사용하면 계속 나아갈 수있는 기초를 얻을 수있었습니다. 슬프게도 RegEx에 능숙하지는 않지만, 여전히 향상 될 수 있다고 생각하는 코드로 끝났습니다. –

0

확실하지?

+0

감사합니다. 아마도 충분히 명확하지 않았습니다. 코드가 문제의 절반을 해결하고, 후반부가이 새로운 순서로 다시 쓰는 방법입니다. –