加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如何加速循环?是否有一个课程来替换多个术语?

发布时间:2020-12-15 08:08:54 所属栏目:百科 来源:网络整理
导读:循环: var pattern = _dict[key];string before;do{ before = pattern; foreach (var pair in _dict) if (key != pair.Key) pattern = pattern.Replace(string.Concat("{",pair.Key,"}"),string.Concat("(",pair.Value,")"));} while (pattern != before);r
循环:
var pattern = _dict[key];
string before;
do
{
    before = pattern;
    foreach (var pair in _dict)
        if (key != pair.Key)
            pattern = pattern.Replace(string.Concat("{",pair.Key,"}"),string.Concat("(",pair.Value,")"));
} while (pattern != before);
return pattern;

它只是在一堆键上重复查找和替换.字典只是< string,string>.

我可以看到2个改进.

>每次我们执行pattern.Replace它再次从字符串的开头搜索.如果它碰到第一个{,它只会查看匹配的键列表(可能使用二进制搜索),然后替换适当的一个,那会更好.
>模式!=位之前我是如何检查在迭代期间是否有任何替换.如果pattern.Replace函数返回了实际发生的实际替换次数,我不需要这个.

但是……我真的不想写一个很讨厌的东西来做这一切.这必须是一个相当普遍的情况?有没有现成的解决方案?

全班

感谢Elian Ebbing和ChrisWue.

class FlexDict : IEnumerable<KeyValuePair<string,string>>
{
    private Dictionary<string,string> _dict = new Dictionary<string,string>();
    private static readonly Regex _re = new Regex(@"{([_a-z][_a-z0-9-]*)}",RegexOptions.Compiled | RegexOptions.IgnoreCase);

    public void Add(string key,string pattern)
    {
        _dict[key] = pattern;
    }

    public string Expand(string pattern)
    {
        pattern = _re.Replace(pattern,match =>
            {
                string key = match.Groups[1].Value;

                if (_dict.ContainsKey(key))
                    return "(" + Expand(_dict[key]) + ")";

                return match.Value;
            });

        return pattern;
    }

    public string this[string key]
    {
        get { return Expand(_dict[key]); }
    }

    public IEnumerator<KeyValuePair<string,string>> GetEnumerator()
    {
        foreach (var p in _dict)
            yield return new KeyValuePair<string,string>(p.Key,this[p.Key]);
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

示例用法

class Program
{
    static void Main(string[] args)
    {
        var flex = new FlexDict
            {
                {"h",@"[0-9a-f]"},{"nonascii",@"[200-377]"},{"unicode",@"{h}{1,6}(rn|[ trnf])?"},{"escape",@"{unicode}|[^rnf0-9a-f]"},{"nmstart",@"[_a-z]|{nonascii}|{escape}"},{"nmchar",@"[_a-z0-9-]|{nonascii}|{escape}"},{"string1",@"""([^nrf""]|{nl}|{escape})*"""},{"string2",@"'([^nrf']|{nl}|{escape})*'"},{"badstring1",@"""([^nrf""]|{nl}|{escape})*?"},{"badstring2",@"'([^nrf']|{nl}|{escape})*?"},{"badcomment1",@"/*[^*]**+([^/*][^*]**+)*"},{"badcomment2",@"/*[^*]*(*+[^/*][^*]*)*"},{"baduri1",@"url({w}([!#$%&*-[]-~]|{nonascii}|{escape})*{w}"},{"baduri2",@"url({w}{string}{w}"},{"baduri3",@"url({w}{badstring}"},{"comment",@"/*[^*]**+([^/*][^*]**+)*/"},{"ident",@"-?{nmstart}{nmchar}*"},{"name",@"{nmchar}+"},{"num",@"[0-9]+|[0-9]*.[0-9]+"},{"string",@"{string1}|{string2}"},{"badstring",@"{badstring1}|{badstring2}"},{"badcomment",@"{badcomment1}|{badcomment2}"},{"baduri",@"{baduri1}|{baduri2}|{baduri3}"},{"url",@"([!#$%&*-~]|{nonascii}|{escape})*"},{"s",@"[ trnf]+"},{"w",@"{s}?"},{"nl",@"n|rn|r|f"},{"A",@"a|{0,4}(41|61)(rn|[ trnf])?"},{"C",@"c|{0,4}(43|63)(rn|[ trnf])?"},{"D",@"d|{0,4}(44|64)(rn|[ trnf])?"},{"E",@"e|{0,4}(45|65)(rn|[ trnf])?"},{"G",@"g|{0,4}(47|67)(rn|[ trnf])?|g"},{"H",@"h|{0,4}(48|68)(rn|[ trnf])?|h"},{"I",@"i|{0,4}(49|69)(rn|[ trnf])?|i"},{"K",@"k|{0,4}(4b|6b)(rn|[ trnf])?|k"},{"L",@"l|{0,4}(4c|6c)(rn|[ trnf])?|l"},{"M",@"m|{0,4}(4d|6d)(rn|[ trnf])?|m"},{"N",@"n|{0,4}(4e|6e)(rn|[ trnf])?|n"},{"O",@"o|{0,4}(4f|6f)(rn|[ trnf])?|o"},{"P",@"p|{0,4}(50|70)(rn|[ trnf])?|p"},{"R",@"r|{0,4}(52|72)(rn|[ trnf])?|r"},{"S",@"s|{0,4}(53|73)(rn|[ trnf])?|s"},{"T",@"t|{0,4}(54|74)(rn|[ trnf])?|t"},{"U",@"u|{0,4}(55|75)(rn|[ trnf])?|u"},{"X",@"x|{0,4}(58|78)(rn|[ trnf])?|x"},{"Z",@"z|{0,4}(5a|7a)(rn|[ trnf])?|z"},{"CDO",@"<!--"},{"CDC",@"-->"},{"INCLUDES",@"~="},{"DASHMATCH",@"|="},{"STRING",@"{string}"},{"BAD_STRING",@"{badstring}"},{"IDENT",@"{ident}"},{"HASH",@"#{name}"},{"IMPORT_SYM",@"@{I}{M}{P}{O}{R}{T}"},{"PAGE_SYM",@"@{P}{A}{G}{E}"},{"MEDIA_SYM",@"@{M}{E}{D}{I}{A}"},{"CHARSET_SYM",@"@charsetb"},{"IMPORTANT_SYM",@"!({w}|{comment})*{I}{M}{P}{O}{R}{T}{A}{N}{T}"},{"EMS",@"{num}{E}{M}"},{"EXS",@"{num}{E}{X}"},{"LENGTH",@"{num}({P}{X}|{C}{M}|{M}{M}|{I}{N}|{P}{T}|{P}{C})"},{"ANGLE",@"{num}({D}{E}{G}|{R}{A}{D}|{G}{R}{A}{D})"},{"TIME",@"{num}({M}{S}|{S})"},{"PERCENTAGE",@"{num}%"},{"NUMBER",@"{num}"},{"URI",@"{U}{R}{L}({w}{string}{w})|{U}{R}{L}({w}{url}{w})"},{"BAD_URI",@"{baduri}"},{"FUNCTION",@"{ident}("},};

        var testStrings = new[] { @"""str""",@"'str'","5","5.","5.0","a","alpha","url(hello)","url("hello")","url("blah)",@"g",@"/*comment*/",@"/**/",@"<!--",@"-->",@"~=","|=",@"#hash","@import","@page","@media","@charset","!/*iehack*/important"};

        foreach (var pair in flex)
        {
            Console.WriteLine("{0}nt{1}n",pair.Value);
        }

        var sw = Stopwatch.StartNew();
        foreach (var str in testStrings)
        {
            Console.WriteLine("{0} matches: ",str);
            foreach (var pair in flex)
            {
                if (Regex.IsMatch(str,"^(" + pair.Value + ")$",RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture))
                    Console.WriteLine("  {0}",pair.Key);
            }
        }
        Console.WriteLine("nRan in {0} ms",sw.ElapsedMilliseconds);
        Console.ReadLine();
    }
}

目的

用于构建可能相互扩展的复杂正则表达式.也就是说,我正在尝试实施the css spec.

解决方法

我认为如果你使用正则表达式查找{foo}的任何出现会更快,然后使用 MatchEvaluator替换{foo},如果foo恰好是字典中的键.

我目前没有视觉工作室,但我想这在功能上与您的代码示例相同:

var pattern = _dict[key];
bool isChanged = false;

do
{
    isChanged = false;

    pattern = Regex.Replace(pattern,"{([^}]+)}",match => {
        string matchKey = match.Groups[1].Value;

        if (matchKey != key && _dict.ContainsKey(matchKey))
        {
            isChanged = true;
            return "(" + _dict[matchKey] + ")";
        }

        return match.Value;
    });
} while (isChanged);

我可以问你为什么需要do / while循环吗?字典中键的值是否可以再次包含必须替换的{占位符}?你能确定你不会陷入无限循环,其中键“A”包含“Blahblah {B}”而键“B”包含“Blahblah {A}”吗?

编辑:进一步的改进将是:

>使用预编译的正则表达式.
>使用递归而不是循环(参见ChrisWue’s注释).
>使用_dict.TryGetValue(),如Guffa’s代码中所示.

你最终会得到一个O(n)算法,其中n是输出的大小,所以你不能做得比这更好.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读