C#中的递归字符串替换

时间:2011-12-16 05:42:48

标签: c# algorithm replace

塞纳里奥

我有一个对象关键字 - >它有一个名称和一个值(字符串)

关键字不能包含itsSelf ...但可以包含其他关键字示例

K1 = "%K2% %K3% %K4%"

其中K2,K3,K4是关键词......

只是用他们的价值观重新实现它们,但这里有一个我正面临的问题

考试:

K3= "%K2%"

K2= "%K4%"

K4="%K2%"

现在,如果我开始更换,那么将会有一个无限循环,因为K2给出K4和副Versa ......

我希望避免这样的问题

但是我要求我允许uesr嵌套其他关键字...我怎么能检查“添加如果DeadLock发生”我将显示无效...我应该使用HashTable还是什么...... {{ 1}}

5 个答案:

答案 0 :(得分:18)

来自你的评论:

  

我希望能够使用无上下文语法并在其上运行一个分析器,以确定是否存在任何“无限循环”。

这很容易做到。首先,让我们清楚地定义一个“无上下文语法”。 CFG是具有“终端”和“非终端”符号的替代系统。终端是“完成”的东西;非终端用一系列终端和非终端符号代替。

在我的示例中,非终端将处于大写状态,终端将采用小写。替换规则将被写为“NONTERMINAL:替换符号”。所以CFG的一个例子是:

SENTENCE : SUBJECT VERB OBJECT
SUBJECT  : ARTICLE NOUN
ARTICLE  : a
ARTICLE  : the
NOUN     : can
NOUN     : man
VERB     : saw
VERB     : kicked
OBJECT   : ARTICLE NOUN

因此,如果我们从SENTENCE开始,那么我们可以进行替换:

SENTENCE
SUBJECT VERB OBJECT
ARTICLE NOUN VERB OBJECT
the NOUN VERB OBJECT
the man VERB OBJECT
the man kicked OBJECT
the man kicked ARTICLE NOUN
the man kicked the NOUN
the man kicked the can

我们没有更多非终端,所以我们已经完成了。

CFG可以有周期:

EQUATION : TERM = TERM
TERM     : 1
TERM     : ADDITION
ADDITION : TERM + TERM

现在我们做制作:

EQUATION
TERM = TERM
1 = TERM
1 = ADDITION
1 = TERM + TERM
1 = 1 + TERM
1 = 1 + 1

这个人最终可以停止,但也可以永远停止。当然,您可以定义必须永远存在的CFG;如果没有生产“TERM:1”那么这个将永远存在而没有找到只有终端的有效序列。

那么如何确定是否有任何制作可以永久运行?

您所做的是制作有向图数据结构。将所有非终端设置为图中的节点。然后为右侧具有非终端的每个生产规则添加边。所以对于我们的第一个例子,我们有图表:

SENTENCE ----->  SUBJECT
  |   |          |     |
  |   |          |     |
  v   |          |     |
 VERB |          |     |   
      v          v     |
     OBJECT--->ARTICLE |
         \             v  
          ---------->NOUN

在第二个例子中,我们有图表:

EQUATION --> TERM ---> ADDITION
                 <-----/

如果图形包含可从起始符号到达的循环,则语法包含可以永久扩展的作品。如果没有,那就不行了。

所以现在你所要做的就是构建一个循环检测器,这在图形分析中是一个简单的问题。如果没有循环,或者从开始符号无法到达唯一的循环,则语法很好。

答案 1 :(得分:2)

首先,我实际上不会递归地执行此操作。有一个非常好的迭代解决方案,不会破坏您的堆栈:

def morph (string):
    while string has a substitution pattern in it:
        find first keyword in string
        replace it with value
    endwhile
    return string

这是基本结构。没有机会用无限循环替换来消除堆栈空间。但是,它仍然存在与递归解决方案相同的问题,因为它无限循环:

kw1="%kw2%"
kw2="%kw1%"

甚至更简单:

kw1="%kw1%"

阻止 的最佳方法是简单地对允许的替换次数提供任意限制(并且最好使其可配置以防真正需要大量数据)。

你可以将它设为一个任意大的数字,因为没有堆栈井喷的风险,上面代码所需的更改就像这样简单:

def morph (string):
    sublimit = getConfig ("subLimit")
    while string has a substitution pattern in it:
        sublimit = sublimit - 1
        if sublimit < 0:
            return some sort of error
        find first keyword in string
        replace it with value
    endwhile
    return string

答案 2 :(得分:0)

每次要替换关键字时,请将其添加到集合中。如果在某个时刻,该集合包含多次关键字,则它是递归的。然后你可以抛出异常或者跳过它。

答案 3 :(得分:0)

实施唯一关键字。它们可以嵌套但不相等。

由于很难拥有深层嵌套的字符串,因此可以对递归级别强制实施限制。

答案 4 :(得分:0)

这个想法是实现类似“状态”机器的东西:

  1. 查找任何键字符串
  2. 的第一次出现
  3. 在那里更换
  4. 查找任何键字符串的首次出现,从上一个出现(从步骤2开始)
  5. 在那里更换

  6. using System;
    
    class Program
    {
        static void Main(string[] args)
        {
            var s = "%K2% %K3% %K4%";
            var replaces = new[]
                               {
                                   new[] {"%K3%", "%K2%"},
                                   new[] {"%K2%", "%K4%"},
                                   new[] {"%K4%", "%K2%"},
                               };
    
            bool wasReplaces;
            var curPos = 0;
            do
            {
                wasReplaces = false;
    
                string[] curReplacement = null;
                var minIndex = int.MaxValue;
    
                foreach (var replacement in replaces)
                {
                    var index = s.IndexOf(replacement[0], curPos);
                    if ((index < minIndex) && (index != -1))
                    {
                        minIndex = index;
                        curReplacement = replacement;
                    }
                }
    
                if (curReplacement != null)
                {
                    s = s.Substring(0, minIndex) + curReplacement[1] + s.Substring(minIndex + curReplacement[0].Length);
                    curPos = minIndex + curReplacement[0].Length + 1;
                    wasReplaces = true;
                }
    
            } while (wasReplaces && (curPos < s.Length));
    
            // Should be "%K4% %K2% %K2%
            Console.WriteLine(s);
        }
    }