尝试删除字符时陷入无限循环

Posted

技术标签:

【中文标题】尝试删除字符时陷入无限循环【英文标题】:Stuck in infinite loop while trying to remove a char 【发布时间】:2019-07-27 21:32:38 【问题描述】:

我正在做一个将英语翻译成猪拉丁语的项目,以更好地学习字符串。我正在努力的规则是:

如果单词以元音开头,只需在单词末尾添加方式即可。 如果单词以辅音开头,请将第一个元音之前的辅音移到单词末尾并添加 ay。

我可以让元音工作,但如果我遇到一个常数,我就会陷入无限循环。我对编程和C# 相当陌生。任何解决此问题的帮助将不胜感激,并希望能帮助我理解资源。

我尝试使用 text 创建一个 char 并使用 text 创建一个 int 来检查每个字母。不太确定该怎么做。

这是翻译按钮代码:

private void transBtn_Click(object sender, EventArgs e)

    english = engTxtBx.Text;
    english = english.Trim();
    string[] columns = english.Split(' ');
    for (int i = 0; i < columns.Length; i++)
    
        string text = columns[i];
        char first = text[0];
        for (int c = 0; c < text.Length; c++)
        
            char character = text[c];
            //int consonant = text.IndexOf(character);
            if (isVowel(first))
            
                text = text + "way ";
                pigLatin = text;
                plTxtBx.Text += text;
            
            else if (!isVowel(character))
            
                if (isVowel(text[c + 1]))
                
                    text.Remove(text.IndexOf(character), 1);
                    text += character + "ay";
                    pigLatin = text;
                    plTxtBx.Text += text;
                
                break;
            
        
    

public static bool isVowel(char c)

    return new[] 'a','e','i','o','u'.Contains(char.ToLower(c));

如果我输入短语“Can I have a apple”,则应从第一个字符中删除 see 并移至末尾,然后应添加“ay”。现在,当我调试时,c 没有被删除,而是添加到末尾并添加了 ay。然后它卡在“我”上。

【问题讨论】:

【参考方案1】:

我已经进行了一些更改以使其正常工作。在代码中查看我的 cmets。

private void transBtn_Click(object sender, EventArgs e)


    english = engTxtBx.Text;
    english = english.Trim();
    string[] columns = english.Split(' ');
    for (int i = 0; i < columns.Length; i++)
    
        if (isVowel(columns[i][0]))
        
            // Start with vowel.
            pigLatin = columns[i] + "way";
        
        else
        
            // Start with consonant. Get index of first vowel.
            int index = columns[i].IndexOfAny(vowels);
            if (index == -1)
            
                // No vowel in columns[i].
                // You have to decide what to do.
            
            else if (index == 1)
            
                // First vowel is the second letter.
                pigLatin = columns[i].Substring(1) + columns[i][0] + "way";
            
            else
            
                // First vowel is after the second letter.
                pigLatin = columns[i].Substring(index) + columns[i].Substring(index - 1, 1) + "way";
            

        
        plTxtBx.Text += pigLatin;
    



private static char[] vowels =  'a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U' ;

private static bool isVowel(char c)

    return vowels.Contains(c);

【讨论】:

【参考方案2】:

所以 Robert 提供了一个解决方案,但既然你说你是编程新手,我会试着解释这个问题,我会试着用一个简化的例子来说明你正在做什么:

string text = "Hello!";
for(int i = 0; i < text.Length; i++)

     text += "!";

您的循环条件基于 text.Length,但在循环中,您将附加到该文本,因此每次循环准备好重新开始时,它都会检查 text.Length 并说:“好吧,我'm -STILL- 不在 text.Length 的末尾,所以我想我会继续循环。

如果您只想根据初始字符数循环,您应该:

A.在循环之前将 text.Length 存储到一个单独的变量中,然后将循环条件基于它,如下所示:

string text = "Hello!";
int initialLength = text.Length;
for(int i = 0; i < initialLength; i++)

     text += "!";

B.或者更好的是,不要将更多内容附加到您的文本变量上,而是使用单独的字符串变量作为您的“修改”副本:

string text = "Hello!";
string text2 = text;
for(int i = 0; i < text.Length; i++)

     text2 += "!";

C.或者最好的是,采用方法 B,但使用 StringBuilder 类。在 C# 中,当您修改字符串时,系统会在内存中创建一个全新的字符串副本以及额外的字符,因此:

text = "Hello";
text += "!";
text += "!";
text += "!";

...实际上是在内存中创建四个不同的字符串变量:

你好 你好! 你好!! 你好!!!

这是暂时的,但效率低下且浪费。 StringBuilder 类旨在让您高效地逐段构建字符串:

StringBuilder sb = new StringBuilder("Hello");
sb.Append("!");
sb.Append("!");
sb.Append("!");
Console.WriteLine(sb.ToString()); // "Hello!!!"

因此,如果您查看示例 B,您可能会将其更改为:

string text = "Hello!";
StringBuilder sbText = new StringBuilder(text);
for(int i = 0; i < text.Length; i++)

     sbText.Append("!");

我的最终建议是按照您希望的方式获取字符串/内容,然后将其分配给您的控件。所以不要调用这个 10 次:

 plTxtBx.Text += text;

相反,以正确的方式设置文本,然后在最后做一个简单的分配:

 plTxtBx.Text = final_text;

这样做的原因是,当您修改文本等属性时,控件具有各种事件以及运行的小齿轮和齿轮。如果您使用 += 技巧将文本附加到 Textbox 控件,那么您将在每次更新文本时强制控件运行其整个例程。

这些都是小的低效率,但随着时间的推移它们会累积起来,因此最好提前做好。

因此,如果我采用 Robert 提出的代码(我没有亲自测试过)并对其进行一些更改,我会这样做:

private void transBtn_Click(object sender, EventArgs e)

    // Start with whatever is in plTxtBx
    StringBuilder sb = new StringBuilder(plTxtBx.Text); 

    // Break into words
    string[] columns = engTxtBx.Text.Trim().Split(' ');
    for (int i = 0; i < columns.Length; i++)
    
        if (isVowel(columns[i][0]))
        
            // Start with vowel.
            sb.Append(columns[i]);
            sb.Append("way");
        
        else
        
            // Start with consonant. Get index of first vowel.
            int index = columns[i].IndexOfAny(vowels);
            if (index == -1)
            
                // No vowel in columns[i].
                // You have to decide what to do.
            
            else if (index == 1)
            
                // First vowel is the second letter.
                sb.Append(columns[i].Substring(1));
                sb.Append(columns[i][0]);
                sb.Append("way");
            
            else
            
                // First vowel is after the second letter.
                sb.Append(columns[i].Substring(index));
                sb.Append(columns[i].Substring(index - 1, 1));
                sb.Append("way");
            

        
    

    // Update plTxtBx's Text once with the final results
    plTxtBx.Text = sb.ToString();


【讨论】:

我喜欢这个答案。我要提出的唯一其他建议是给变量起有意义的名称——您应该能够查看变量名称并直观地了解它的用途。当您在 6、12 或 60 个月后回来查看事物时,养成良好的命名习惯将减轻您的精神痛苦。所以变量columns 可以称为splitWordssourceWordsenglishWords;变量i 可以称为wordIndexwordNumber;等等…… 嘿,非常感谢,这真的很有帮助。我有两个简单的问题。主要是为了帮助我更好地理解。在代码中 if (isVowel(columns[i][0])) 我知道 [i] 是特定单词,而 [0] 是该单词的第一个索引,但是如何在其中声明这两个索引一行而不是单独的变量。另一个在 sb.Append(columns[i].Substring(index - 1, 1));索引 -1 是否将其退回到最后一个字符,以及 1 到底在做什么?再次感谢您的帮助。 @RobertBaron - 这取决于文本的长度。我们不能假设 1 或 2 个串联。如果这是翻译文本段落,那么节省的费用可能很大。是的,我在文本框上将 += 更改为 = 并将其移出循环并解释了原因。所以我不确定你指的是什么...... @greel87 - 在某些情况下,代码可以让你走捷径。该代码足够聪明,可以理解 [0] 是列 [I] 的第一个索引,这正是您的措辞。您并不总是使用单独的变量。也就是说,考虑到 column[I] 被引用的次数,我会考虑为它创建一个名为 word (string word = columns [i];) 的单独变量,并使用该变量来代替更易读的代码。 @greel87 - 假设变量索引为 22,代码 Substring(index - 1, 1) 表示“转到位置 21 并抓取 1 个字符”,因此它正在抓取前一个字符。

以上是关于尝试删除字符时陷入无限循环的主要内容,如果未能解决你的问题,请参考以下文章

为啥应用程序在设置属性时会陷入无限循环?

Spring Batch SkipPolicy在处理异常时陷入无限循环

为啥当我实现以 2^20 为底的基数排序以对大小为 500 万的数组进行排序时,该程序会陷入无限循环?

HAL_Delay() 陷入无限循环

Bash参数解析逻辑陷入无限循环[重复]

c++:在修改 c 字符串数组时帮助纠正无限循环