他の人が言ったように、パターンには 1 つのグループしかないため、s ではMatch
なく esをループする必要があります。Group
これを行う通常の方法は、Michael Gunter のfor
ループまたは単に
Match m = reg.Match(line);
while(m.Success)
{
// read class from m.Groups[1]
m = m.NextMatch();
}
ただし、最終的な問題を解決するには、すべてのデータを個別に取得して文字列を元に戻すのは少し面倒かもしれません。特に、この置換を複数行で一度に行いたい場合はなおさらです。
Regex.Replace
したがって、 (コールバックを受け取るバージョン)を調べることをお勧めします。そうすれば、すべてを 1 回の一致で一致させることができ、.NET の独自の機能を利用して、1 つのグループの複数のキャプチャにアクセスできます。
var line = "<!C43!><!TG!>Some Characters";
MatchEvaluator evaluator = new MatchEvaluator(ReplaceCallback);
string output = Regex.Replace(
line,
@"(?:<!([^<>]+)!>)+(.+)",
evaluator
);
そしてあなたのクラスのどこかで:
static string ReplaceCallback(Match match)
{
var sb = new StringBuilder("<span class=\"");
sb.Append(match.Groups[1].Captures[0].Value);
for(int i = 1; i < match.Groups[1].Captures.Count; i++)
{
sb.Append(" ");
sb.Append(match.Groups[1].Captures[i].Value);
}
sb.Append("\">");
sb.Append(match.Groups[2].Value);
sb.Append("</span>");
return sb.ToString();
}
文字列を設定する方がおそらく簡単ですString.Format
が、現時点でString.Join
はCaptureCollection
.
だから、これは基本的に何をしているのか:
パターン@"(?:<!([^<>]+)!>)+(.+)"
は 1 つ以上の<!...!>
「トークン」に一致し、次に行の残りの部分に一致します。そうしている間に、の内容をキャプチャし<!...!>
ます。繰り返しごとに別のキャプチャが記録され、後でコールバックでそれらすべてにアクセスできます。トークンの後、<!...!>
行の残りを で照合してキャプチャし(.+)
ます。文字列の前にあることに注意してください@
: これにより、文字列が逐語的に作成されます。これは、正規表現パターンを指定するときに常に行う必要があります。そうしないと、エスケープに関して問題が発生します。?:
また、最初の左括弧の後に注意してください。<!
これは、区切り文字を含む別のキャプチャが必要ないため、キャプチャを抑制するためです!>
。実際にキャプチャする必要がない限り、常に非キャプチャ グループを使用することも良い方法です。
コールバック関数は、入力の一致ごとに呼び出されます。行全体を含む一致は 1 つだけです。この試合では、 group で 2 つのトークンがキャプチャされ1
、残りの行は group でキャプチャされました2
。
したがって、 で始まる文字列を簡単に作成できます。次に、 <span ="
group のすべてのキャプチャのスペース区切りリスト、1
次に">
キャプチャされた残りの行、最後に</span>
.
先ほど言ったようにString.Join
、コレクション グループへの道を見つけると、コールバック関数は 3 行ほどに減ります。
とMatch
の区別がまだ少し曖昧な場合は、コールバック関数にブレークポイントを設定し、そこでオブジェクトを調べることをお勧めします。Group
Capture
match