C#递归方法的意外结果

C#递归方法的意外结果,c#,html,string,text,recursion,C#,Html,String,Text,Recursion,我有一个非常简单的方法,可以递归地删除开始/结束html标记 class Program { static void Main(string[] args) { string s = FixHtml("<div><p>this is a <strong>test</strong></p></div>"); Console.Write

我有一个非常简单的方法,可以递归地删除开始/结束html标记

class Program
    {   
        static void Main(string[] args)
        {
            string s = FixHtml("<div><p>this is a <strong>test</strong></p></div>");
            Console.WriteLine(s);
        }

        private static string FixHtml(string s)
        {            
            //Remove any outer <div>
            if (s.ToLower().StartsWith("<div>"))
            {
                FixHtml(s.Substring(5, s.Length - 5));
            }
            else if (s.ToLower().StartsWith("<p>"))
            {
                FixHtml(s.Substring(3, s.Length - 3));
            }
            else if (s.ToLower().EndsWith("</div>"))
            {
                FixHtml(s.Substring(0, s.Length - 6));
            }
            else if (s.ToLower().EndsWith("</p>"))
            {
                FixHtml(s.Substring(0, s.Length - 4));
            }

            return s;
        }
    }
类程序
{   
静态void Main(字符串[]参数)
{
字符串s=FixHtml(这是一个测试

”; 控制台。写入线(s); } 私有静态字符串FixHtml(字符串s) { //拆下任何外部组件 如果(s.ToLower().StartsWith(“”) { FixHtml(s.Substring(5,s.Length-5)); } else if(s.ToLower().StartsWith(“”) { FixHtml(s.Substring(3,s.Length-3)); } else if(s.ToLower().EndsWith(“”) { FixHtml(s.Substring(0,s.Length-6)); } else if(s.ToLower().EndsWith(“

”) { FixHtml(s.Substring(0,s.Length-4)); } 返回s; } }
其行为是,它可以递归地删除
&
标记,但在“returns”语句中,通过添加回添加标记,撤消所有工作


有人知道为什么会这样吗?我如何强制它返回我想要的值。i、 e
这是一个测试

在.NET中,字符串是不可变的-因此您的方法实际上从不更改返回值。当您调用
s.ToLower().StartsWith(“”)时,您将返回一个具有预期差异的新字符串。现有字符串s保持不变

此外,您从不使用递归调用的返回值

在我的脑海里,试着这样做:

    private static string FixHtml(string s)
    {            
        if (s.ToLower().StartsWith("<div>"))
        {
            return FixHtml(s.Substring(5, s.Length - 5));
        }
        else if (s.ToLower().StartsWith("<p>"))
        {
            return FixHtml(s.Substring(3, s.Length - 3));
        }
        else if (s.ToLower().EndsWith("</div>"))
        {
            return FixHtml(s.Substring(0, s.Length - 6));
        }
        else if (s.ToLower().EndsWith("</p>"))
        {
            return FixHtml(s.Substring(0, s.Length - 4));
        }

        return s;
    }
   private static string FixHtml(string s)
    {            
        //Remove any outer <div>
        if (s.ToLower().StartsWith("<div>"))
        {
            return FixHtml(s.Substring(5, s.Length - 5));
        }
        else if (s.ToLower().StartsWith("<p>"))
        {
            return FixHtml(s.Substring(3, s.Length - 3));
        }
        else if (s.ToLower().EndsWith("</div>"))
        {
            return FixHtml(s.Substring(0, s.Length - 6));
        }
        else if (s.ToLower().EndsWith("</p>"))
        {
            return FixHtml(s.Substring(0, s.Length - 4));
        }

        return s;
    }
private静态字符串FixHtml(字符串s)
{            
如果(s.ToLower().StartsWith(“”)
{
返回FixHtml(s.Substring(5,s.Length-5));
}
else if(s.ToLower().StartsWith(“”)
{
返回FixHtml(s.Substring(3,s.Length-3));
}
else if(s.ToLower().EndsWith(“”)
{
返回FixHtml(s.Substring(0,s.Length-6));
}
else if(s.ToLower().EndsWith(“

”) { 返回FixHtml(s.Substring(0,s.Length-4)); } 返回s; }
  • 您没有对嵌套调用返回的字符串执行任何操作
  • 更改字符串时,将创建一个新对象,而不是更改现有对象(它们是不可变的)
  • 如果希望采用类似的方法而不使用返回值,可以将字符串参数设置为“ref”参数。尽管其他人提到的性能下降仍然适用

您需要向每个FixHtml调用添加一个返回,如下所示:

    private static string FixHtml(string s)
    {            
        if (s.ToLower().StartsWith("<div>"))
        {
            return FixHtml(s.Substring(5, s.Length - 5));
        }
        else if (s.ToLower().StartsWith("<p>"))
        {
            return FixHtml(s.Substring(3, s.Length - 3));
        }
        else if (s.ToLower().EndsWith("</div>"))
        {
            return FixHtml(s.Substring(0, s.Length - 6));
        }
        else if (s.ToLower().EndsWith("</p>"))
        {
            return FixHtml(s.Substring(0, s.Length - 4));
        }

        return s;
    }
   private static string FixHtml(string s)
    {            
        //Remove any outer <div>
        if (s.ToLower().StartsWith("<div>"))
        {
            return FixHtml(s.Substring(5, s.Length - 5));
        }
        else if (s.ToLower().StartsWith("<p>"))
        {
            return FixHtml(s.Substring(3, s.Length - 3));
        }
        else if (s.ToLower().EndsWith("</div>"))
        {
            return FixHtml(s.Substring(0, s.Length - 6));
        }
        else if (s.ToLower().EndsWith("</p>"))
        {
            return FixHtml(s.Substring(0, s.Length - 4));
        }

        return s;
    }
private静态字符串FixHtml(字符串s)
{            
//拆下任何外部组件
如果(s.ToLower().StartsWith(“”)
{
返回FixHtml(s.Substring(5,s.Length-5));
}
else if(s.ToLower().StartsWith(“”)
{
返回FixHtml(s.Substring(3,s.Length-3));
}
else if(s.ToLower().EndsWith(“”)
{
返回FixHtml(s.Substring(0,s.Length-6));
}
else if(s.ToLower().EndsWith(“

”) { 返回FixHtml(s.Substring(0,s.Length-4)); } 返回s; }
您需要使用
StringBuilder
才能工作,或者在每次调用
FixHTML
时复制字符串才能工作。这是因为字符串在.NET中是不可变的


您可以查看什么是不可变字符串。

如果您计划在服务器上执行此操作,则必须使用字符串生成器。原因是如果使用字符串,内存性能将非常糟糕。每次从字符串中删除标记时,都会有效地复制字符串。对于每个递归(标记),您的系统都会这样做,因此,如果您有一个合理大小的HTML输入,您将很快使用大量内存

编辑:参考Chris的评论,如果您处理的是大字符串,那么前面的语句是正确的。如果您正在使用字符串生成器解析小的HTML块,那么就没有那么重要了。但我假设您在web环境中的服务器上使用它,因此您可能会使用它来消耗非常大的页面

使用字符串生成器作为引用也将允许函数操作可变值,因此在递归结束时,StringBuilder.ToString()将正确输出经过变异的字符串

如果你支持我的解决方案,你应该支持那些把字符串易变性作为你的问题的人:)

我试图回答你的问题,并解决下一个问题,相信我,这是许多人以前犯过的错误

还请注意,您的代码将在

private static string FixHtml(StringBuilder bldr)    
{                    
    if (String.Compare(blder.ToString(0,5), "<div>", true) == 0)        
    {
        blder.remove(0, 5);            
        return FixHtml(blder);        
    }       
    else if (String.Compare(blder.ToString(0,3), "<p>", true) == 0)       
    {
        blder.remove(0, 3);            
        return FixHtml(blder);             
    }        
    else if (String.Compare(blder.ToString(bldr.Length - 6, 6), "</div>", true) == 0)       
    {
        blder.remove(blder.Length - 6, 6);            
        return FixHtml(blder);                   
    }        
    else if (String.Compare(blder.ToString(bldr.Length - 4, 4), "</p>", true) == 0)       
    {        
        blder.remove(blder.Length - 4, 4);            
        return FixHtml(blder); 
    }       
    return blder.ToString();    
}
私有静态字符串FixHtml(StringBuilder bldr)
{                    
if(String.Compare(blder.ToString(0,5),“”,true)==0)
{
b.移除(0,5);
返回FixHtml(blder);
}       
else if(String.Compare(blder.ToString(0,3),“”,true)==0)
{
b.移除(0,3);
返回FixHtml(blder);
}        
else if(String.Compare(blder.ToString(bldr.Length-6,6),“”,true)==0)
{
b.移除(b.长度-6,6);
返回FixHtml(blder);
}        
else if(String.Compare(blder.ToString(bldr.Length-4,4),“

”,true)==0) { b.移除(b.长度-4,4); 返回FixHtml(blder); } 返回blder.ToString(); }
请注意,原始文本操作通常是处理xml的一种糟糕方法-例如,您目前没有处理属性、名称空间、尾随标记空白
)等

通常,我会说