尝试删除字符时陷入无限循环
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
可以称为splitWords
、sourceWords
或englishWords
;变量i
可以称为wordIndex
或wordNumber
;等等……
嘿,非常感谢,这真的很有帮助。我有两个简单的问题。主要是为了帮助我更好地理解。在代码中 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在处理异常时陷入无限循环