2

GroupCollectionキャプチャで s を使用してアイテム ID のグループをキャプチャする正規表現があります(これはコンマで区切ることができ、最後の ID に「and」という単語を含めることもできます)。

(\bItem #(?<ITEMID>\d+))|(,\s?(?<ITEMID>\d+))|(,?\sand\s(?<ITEMID>\d+))

C# のRegexクラスを使用して ITEMID 番号を URL に置き換える簡単な方法はありますか? 現在、私は次のものを持っています:

foreach (Match match in matches)
{
    var group = match.Groups["ITEMID"];
    var address = String.Format(UnformattedAddress, group.Value);

    CustomReplace(ref myString, group.Value, address,
        group.Index, (group.Index + group.Length));
}

public static int CustomReplace(ref string source, string org, string replace,
    int start, int max)
{
    if (start < 0) throw new System.ArgumentOutOfRangeException("start");
    if (max <= 0) return 0;

    start = source.IndexOf(org, start);

    if (start < 0) return 0;

    var sb = new StringBuilder(source, 0, start, source.Length);

    var found = 0;
    while (max-- > 0)
    {
        var index = source.IndexOf(org, start);

        if (index < 0) break;

        sb.Append(source, start, index - start).Append(replace);
        start = index + org.Length;
        found++;
    }

    sb.Append(source, start, source.Length - start);
    source = sb.ToString();

    return found;
}

CustomReplace文字列ソース内の文字列を別の文字列に置き換える簡単な方法としてオンラインで見つけた方法。問題は、おそらくクラスを使用して必要に応じて sRegexを置き換える、より簡単な方法があると確信していることです。GroupCollection私はそれが何であるか理解できません。ありがとう!

テキスト例:

Hello the items you are looking for are Item #25, 38, and 45. They total 100 dollars.

2538、および45は、作成中の URL 文字列 (これは HTML 文字列です) に置き換える必要があります。

4

3 に答える 3

2

あなたのパターンはあなたの入力に対して機能しますが、バグがあります。具体的には、コンマまたは単語" and "の後にある入力の任意の数字と一致します。

この問題を回避するために、パターンを書き直しました。これを実現するために、実際には 2 つの正規表現パターンを使用しています。1 つのパターンを使用してこれを実行することは可能ですが、かなり複雑で、共有することを選択したアプローチよりも読みにくいものです。

主なパターンは次のとおり\bItem #\d+(?:,? \d+)*(?:,? and \d+)? です。アイテムの照合のみに関心があるため、ここではキャプチャ グループは使用されません。ビットは(?: ... )非キャプチャ グループです。の使用法は(?:,? \d+)*、文字列の中間部分にある複数のカンマ区切りの値に一致させることです。

アイテムが一致したら、 を使用Regex.Replaceしてアイテムをフォーマットし、文字列を再構築して、元のアイテムをフォーマットされたアイテムと交換します。

いくつかの異なる入力の例を次に示します。

string[] inputs =
{
    "Hello the items you are looking for are Item #25, 38, 22, and 45. They total 100 dollars.",
    "... Item #25, 38 and 45. Other numbers 100, 20, and 30 untouched.",
    "Item #25, and 45",
    "Item #25 and 45",
    "Item #25"
};

string pattern = @"\bItem #\d+(?:,? \d+)*(?:,? and \d+)?";
string digitPattern = @"(\d+)";
// $1 refers to the first (and only) group in digitPattern
string replacement = @"<a href=""http://url/$1.html"">$1</a>";

foreach (var input in inputs)
{
    Match m = Regex.Match(input, pattern);
    string formatted = Regex.Replace(m.Value, digitPattern, replacement);
    var builder = new StringBuilder(input)
                        .Remove(m.Index, m.Length)
                        .Insert(m.Index, formatted);
    Console.WriteLine(builder.ToString());
}

正規表現置換パターンを使用する代わりに、既存のメソッドを使用して URL をフォーマットする必要がある場合Regex.Replaceは、MatchEvaluator. これはラムダを使用して実現でき、MSDN ドキュメントに示されている退屈なアプローチよりも優れています。

たとえばFormatItem、文字列を受け取り、フォーマットされた文字列を返すメソッドがあるとします。

public string FormatItem(string item)
{
    return String.Format("-- {0} --", item);
}

使用するには、前のコード サンプルで使用しFormatItemたメソッドを次のように変更します。Regex.Replace

string formatted = Regex.Replace(m.Value, digitPattern,
                       d => FormatItem(d.Value));
于 2012-06-30T05:47:31.307 に答える
0

あなたは一度に2つの方向からこれに来ているようです. 一方では、3 つのキャプチャ グループを含む正規表現を取得しているため、ソリューションには GroupCollection が含まれていると予想されます。一方、3 つのグループはすべて同じ名前であるため、同じグループの個別のキャプチャ (CaptureCollection) として扱う必要がある場合があります。実際には、おそらくどちらも必要ありません。これがあなたの正規表現です(少し美的な調整をした後):

string source = @"Total cost for Item #25, 38, and 45 is 100 dollars.";

Regex regex1 = new Regex(
    @"\bItem #(?<ITEMID>\d+)|,\s*(?<ITEMID>\d+)|,?\s+and\s+(?<ITEMID>\d+)",
    RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);

foreach (Match m in regex1.Matches(source)) {
  Console.WriteLine(m.Groups["ITEMID"].Value);
}

2538、期待どおりに出力45されます。各選択肢には独自のキャプチャ グループのコピーがありますが、各試合に参加するのはそのうちの 1 つだけです。これは、.NET 正規表現フレーバーの注目すべき機能です。他のいくつかは、グループ名の再利用を可能にする特別な設定またはグループ構造を提供しますが、.NET ほど簡単なものはありません。ただし、この場合は実際には必要ありません。次のように、代替案をマージするだけです。

@"(\bItem #|,\s*|,?\s+and\s+)(?<ITEMID>\d+)"

ただし、正規表現には問題があり、ソース文字列を次のように変更すると明らかになります。

@"Total cost for Item #25, 38, and 45 is 1,500 dollars and 42 cents."

出力は253845500、 になり42ました。これらの誤検知を防ぐには、 で始まらない各一致Item #が、最後の一致が終了した場所から開始するようにする必要があります。そのために使用できます\G

@"(\bItem #|\G,?\s+and\s+|\G,\s*)(?<ITEMID>\d+)"

(効率のために、最後の 2 つの選択肢の順序も入れ替えました。) これらをすべてまとめると、別の正規表現置換が得られます。

string source =
   @"Total cost for Item #25, 38, and 45 is 1,500 dollars and 42 cents.";
Regex regex2 = new Regex(
    @"(?<TEXT>\bItem #|\G,?\s+and\s+|\G,\s*)(?<ITEMID>\d+)",
    RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
string result = regex2.Replace(source, 
    @"${TEXT}<a href='URL_${ITEMID}'>${ITEMID}</a>");
Console.WriteLine(result);

GroupCollections または CaptureCollections を明示的に使用する必要はありません。置換がこれよりもはるかに複雑でない限り、おそらく MatchEvaluator も必要ありません。

于 2012-07-01T04:55:56.657 に答える
0

必要な構文の例を次に示します。また、コールバックを介して置換で C# に戻すことができることも示しています。

Regex.Replace の MatchEvaluator はどのように機能しますか?

于 2012-06-29T19:09:47.770 に答える