0

String.Replaceすでに置換されたテキストを置換せずに複数を実行するための賢明なアプローチは何ですか。たとえば、次の文字列があるとします。

str = "Stacks be [img]http://example.com/overflowing.png[/img] :/";

私が書いた正規表現は に一致[img]url[/img]し、適切な HTML 形式に置き換えます<img>

str = "Stacks be <img src=\"http://example.com/overflowing.png\"/> :/";

その後、絵文字コード ( 、、など) をタグString.Replaceに置き換える作業を行います。ただし、意図しない結果があります。:/:(:P<img>

意図した結果

str = "Stacks be <img src=\"http://example.com/overflowing.png\"/> " + 
    "<img src=\"emote-sigh.png\"/>";

実際の(そして明らかな)結果

str = "Stacks be <img src=\"http<img src=\"emote-sigh.png"/> " + 
    "/example.com/overflowing.png\"/>" + 
    "<img src=\"emote-sigh.png\"/>";

残念ながら、私が計画している置換の数では、単一の正規表現ですべてを実行しようとするのは現実的ではないようです (ただし、それが最もパフォーマンスの高いソリューションになると思います)。これを行う(遅いが)より保守しやすい方法は何ですか?

4

8 に答える 8

3

残念ながら、私が計画している置換の数では、単一の正規表現ですべてを実行しようとするのは現実的ではないようです (ただし、それが最もパフォーマンスの高いソリューションになると思います)。これを行う(遅いが)より保守しやすい方法は何ですか?

そう思われるかもしれませんが、そうではありません。この記事を見てください。

tl;dr: Replace2 番目の引数としてデリゲートを受け入れます。したがって、同時に置き換えたいすべての異なるものの分離であるパターンに一致し、デリゲートで aDictionaryまたは aswitchまたは同様の戦略を使用して、現在の要素の正しい置換を選択します。

この記事の戦略は、キーが静的文字列であることに依存しています。キーに正規表現演算子がある場合、この概念は失敗します。キーをキャプチャ括弧でラップすることにより、適切なキャプチャ グループの存在をテストして、どのブレースが一致したかを確認する、より良い方法があります。

于 2013-10-08T06:00:35.347 に答える
3

最も明白なアプローチは、正規表現を使用して、必要なテキストを置き換えることです。要するに、次のような正規表現を使用できます: :/[^/]to match :/but not ://.

グループを使用して、一致したパターンを知ることもできます。これにより、何を配置するかを知ることができます。

于 2013-10-08T06:00:58.340 に答える
2

もう 1 つの方法は、一種の修正されたレクサーを使用して、特定の置換が保証されるテキスト内の個別の領域をそれぞれ分離し、そのブロックで置換が再度実行されないようにマークすることです。

これを行う方法の例を次に示します。

まず、特定の文字列が使用されているかどうかを示すクラスを作成します

public class UsageIndicator
{
    public string Value { get; private set; }

    public bool IsUsed { get; private set; }

    public UsageIndicator(string value, bool isUsed)
    {
        Value = value;
        IsUsed = isUsed;
    }

    public override string ToString()
    {
        return Value;
    }
}

次に、テキスト内の「トークン」を見つける方法と、見つかった場合の対処方法の両方を表すクラスを定義します。

public class TokenOperation
{
    public Regex Pattern { get; private set; }

    public Func<string, string> Mutator { get; private set; }

    public TokenOperation(string pattern, Func<string, string> mutator)
    {
        Pattern = new Regex(pattern);
        Mutator = mutator;
    }

    private List<UsageIndicator> ExtractRegions(string source, int index, int length, out int matchedIndex)
    {
        var result = new List<UsageIndicator>();
        var head = source.Substring(0, index);
        matchedIndex = 0;

        if (head.Length > 0)
        {
            result.Add(new UsageIndicator(head, false));
            matchedIndex = 1;
        }

        var body = source.Substring(index, length);
        body = Mutator(body);
        result.Add(new UsageIndicator(body, true));

        var tail = source.Substring(index + length);

        if (tail.Length > 0)
        {
            result.Add(new UsageIndicator(tail, false));
        }

        return result;
    }

    public void Match(List<UsageIndicator> source)
    {
        for (var i = 0; i < source.Count; ++i)
        {
            if (source[i].IsUsed)
            {
                continue;
            }

            var value = source[i];
            var match = Pattern.Match(value.Value);

            if (match.Success)
            {
                int modifyIBy;
                source.RemoveAt(i);
                var regions = ExtractRegions(value.Value, match.Index, match.Length, out modifyIBy);

                for (var j = 0; j < regions.Count; ++j)
                {
                    source.Insert(i + j, regions[j]);
                }

                i += modifyIBy;
            }
        }
    }
}

これらのことを処理した後、交換を行うために何かを組み立てるのは非常に簡単です

public class Rewriter
{
    private readonly List<TokenOperation> _definitions = new List<TokenOperation>();

    public void AddPattern(string pattern, Func<string, string> mutator)
    {
        _definitions.Add(new TokenOperation(pattern, mutator));
    }

    public void AddLiteral(string pattern, string replacement)
    {
        AddPattern(Regex.Escape(pattern), x => replacement);
    }

    public string Rewrite(string value)
    {
        var workingValue = new List<UsageIndicator> { new UsageIndicator(value, false) };

        foreach (var definition in _definitions)
        {
            definition.Match(workingValue);
        }

        return string.Join("", workingValue);
    }
}

デモ コード (以下) では、パターンまたはリテラル式を追加する順序が重要であることに注意してください。最初に追加されたものは最初にトークン化されるため、://URL 内の が顔文字とスラッシュとして選択されるのを防ぐために、最初に画像ブロックを処理します。これは、タグの間に URL が含まれ、次のようにマークされるためです。絵文字ルールがそれを取得しようとする前に使用されます。

class Program
{
    static void Main(string[] args)
    {
        var rewriter = new Rewriter();
        rewriter.AddPattern(@"\[img\].*?\[/img\]", x => x.Replace("[img]", "<img src=\"").Replace("[/img]", "\"/>"));
        rewriter.AddLiteral(":/", "<img src=\"emote-sigh.png\"/>");
        rewriter.AddLiteral(":(", "<img src=\"emote-frown.png\"/>");
        rewriter.AddLiteral(":P", "<img src=\"emote-tongue.png\"/>");

        const string str = "Stacks be [img]http://example.com/overflowing.png[/img] :/";
        Console.WriteLine(rewriter.Rewrite(str));
    }
}

サンプルは以下を出力します。

Stacks be <img src="http://example.com/overflowing.png"/> <img src="emote-sigh.png"/>
于 2013-10-08T06:26:37.060 に答える
0

これは私の古いプロジェクトのコード スニペットです。

private string Emoticonize(string originalStr)
{
    StringBuilder RegExString = new StringBuilder(@"(?<=^|\s)(?:");
    foreach (KeyValuePair<string, string> e in Emoticons)
    {
        RegExString.Append(Regex.Escape(e.Key) + "|");
    }
    RegExString.Replace("|", ")", RegExString.Length - 1, 1);
    RegExString.Append(@"(?=$|\s)");
    MatchCollection EmoticonsMatches = Regex.Matches(originalStr, RegExString.ToString());

    RegExString.Clear();
    RegExString.Append(originalStr);
    for (int i = EmoticonsMatches.Count - 1; i >= 0; i--)
    {
        RegExString.Replace(EmoticonsMatches[i].Value, Emoticons[EmoticonsMatches[i].Value], EmoticonsMatches[i].Index, EmoticonsMatches[i].Length);
    }

    return RegExString.ToString();
}

Emoticons は、顔文字コードをキーとして格納し、対応する画像を値として格納した Dictionary です。

于 2013-10-08T06:16:50.643 に答える
0
        string[] emots = { ":/", ":(", ":)" };
        string[] emotFiles = { "emote-sigh", "emot-sad.png", "emot-happy.png" };

        string replaceEmots(string val)
        {
            string res = val;
            for (int i = 0; i < emots.Length; i++)
                res = res.Replace(emots[i], "<img src=\"" + emotFiles[i] + ".png\"/>");
            return res;
        }

        void button1_click()
        {
            string str = "Stacks be <img src=\"http://example.com/overflowing.png\"/> :/";
            str = replaceEmots(str);
        }
于 2013-10-08T06:22:44.227 に答える
0

これが私の場合に置き換えを行ったコードです。そして、出力はまさにあなたが望むものです。

    str = "Stacks be <img src=\"http://example.com/overflowing.png\"/> :/";


        // check if the htmltemplate hold any template then set it or else hide the div data.
        if (!String.IsNullOrEmpty(str))
        {
            divStaticAsset.InnerHtml = str.Replace("[img]", "<img src=\'").
                                                    Replace("[/img]", "\'/>") + "<img src=\'emote-sigh.png'/>";

        }
于 2013-10-08T06:40:13.380 に答える
0

以下のように置き換えることができます

string.replace( string.replace("[img]","<img src=\""),"[/img]","\"/>")

それはうまくいくはずです。

于 2013-10-08T06:00:16.787 に答える