在字符串中删除和添加字母

4

我正在尝试解决一个C#问题。

这是任务:

  • 如果一个单词以元音字母(a、e、i、o、u或A、E、I、O、U)开头,删除第一个字母并将其附加到末尾,然后添加"che"。例如,单词“orange”翻译为“rangeoche”。
  • 如果一个单词以辅音字母(即不是元音字母)开头,则将"che"附加到单词的末尾。例如,“chicken”变成了“chickenche”。
  • 如果单词的长度是偶数,则在其末尾再添加一个"e"

打印翻译后的句子。

示例:

Hello there Amy

输出:

Helloche thereche myAche

这是我目前为止所做的:

        string Sentence = Console.ReadLine();
        string[] output = Sentence.Split(' ');
        char letter;
        string che = "che";
        StringBuilder sb = new StringBuilder(Sentence);
        foreach (string s in output)
        {
            letter = s[0];

            if (letter == 'a' || letter == 'A' || letter == 'e' || letter == 'E' || letter == 'i'
            || letter == 'I' || letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
            {
             //  Console.WriteLine("first char of the word is a vowel");
            }
            else
            {
                sb.Insert(s.Length,che);
              //  Console.WriteLine("first char of a word is a consonant");
            }

            if (s.Length % 2 == 0)
            {
              //  Console.WriteLine("the word has even numbers of letters");
            }
            //Console.WriteLine(firstchar);
            int currentWordLength = s.Length;

        }
        Console.WriteLine(sb);

问题在于我无法添加"che"或删除单词中的元音字母,因为这些更改会导致索引移动。我只能更改第一个单词。如果我取消注释Console.Writelines,它们会扫描每个单词,我的条件语句是正确的。 我只是难以添加/删除每个单词。您可以指点我正确的方向吗?

3
不需要用StringBuilder,那只会分散注意力(除非你特别被指示要使用它)。想象一下:如果一个字符串以元音字母开头,就取出字符串剩余的部分(元音字母后面的部分),并将这个元音字母添加到剩余的部分中。将字符串拼接在一起形成新字符串很简单,只需使用“+”符号即可。 :-) 请注意,这不需要移动原始源字符串中的元音字母,只需使用我提到的部分来创建一个新字符串... - user2819245
请注意,在所有情况下都要添加“che” - 因此将其作为一种常见情况。你如何处理y? - NetMage
@elgonzo。非常感谢,它起作用了!!我已经按照您的建议进行了操作。 在元音下,我创建了 string newword = s.Substring(1) + s[0] + "che"; 在辅音下: string newword = s + "che"; 在每种情况下,我都检查了单词的长度是偶数还是奇数,并为每个条件添加了if语句。 例如,在元音情况下,如果长度%2 = 0,则使用Console.Write(newword +“e”+“”); 否则 Console.Write(newword +“”); 在辅音情况下,我遵循相同的逻辑。 我还不理解正则表达式和方法,而且我刚开始使用StringBuilder。 - grozdeto
7个回答

1

让我们从使用提取方法将初始问题拆分为更小的问题开始:

  using using System.Text.RegularExpressions;

  ...

  private static String ConvertWord(string word) {
    //TODO: Solution here 
    return word; // <- Stub
  }

  private static String ConvertPhrase(string phrase) {
    // Regex (not Split) to preserve punctuation: 
    // we convert each word (continued sequence of letter A..Z a..z or ')
    // within the original phrase 
    return Regex.Replace(phrase, @"[A-Za-z']+", match => ConvertWord(match.Value));

    // Or if there's guarantee, that space is the only separator:
    // return string.Join(" ", phrase
    //   .Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries) 
    //   .Select(item => ConvertWord(item)));
  }

现在是实现 ConvertWord 的时候了:
  private static String ConvertWord(string word) {
    // Do not forget of special cases - e.g. empty string
    if (string.IsNullOrEmpty(word)) 
      return "chee";

    //  If the word has even number of letters append one more "e" to the end of it. 
    string suffix = word.Length % 2 == 0 ? "chee" : "che"; 

    // To cases: starting from vowel / consonant
    char letter = char.ToUpper(word[0]); 

    if (letter == 'A' || letter == 'E' || letter == 'I' || letter == 'O' || letter == 'U')
      return word.Substring(1) + word.Substring(0, 1) + suffix;
    else
      return word + suffix;
  }

最终
  string Sentence = Console.ReadLine();

  Console.Write(ConvertPhrase(Sentence));

用于测试输入

"It's just a simple test (demo only): nothing more!"

将会得到
t'sIchee justchee ache simplechee testchee (demochee nlyochee): nothingche morechee!

2
正则表达式,当它显然是初学者的作业或学习练习时呢? - InBetween
@InBetween:对于“Regex”(相当简单)我感到很抱歉,但似乎这是提取单词的最简单方法,即使句子中有标点符号:“Split”将得到“(demo”,而不是“demo”。有些作业实际上比它们应该的更难。 - Dmitry Bychenko
1
我更倾向于认为是你把它弄得比必要的更难。OP中绝对没有关于标点符号的要求,也不像是考虑到这种输入的作业难度水平。 - InBetween

1
我建议您创建一个 StringBuilder 对象,并将适当的 string 添加到 IF 条件中。请尝试以下代码:
    string Sentence = Console.ReadLine();
    string[] output = Sentence.Split(' ');
    char letter;
    string che = "che";
    StringBuilder sb = null;
    Console.WriteLine("\n");
    string strFinal = "";
    foreach (string s in output)
    {
        letter = s[0];
        sb = new StringBuilder(s);

        if (letter == 'a' || letter == 'A' || letter == 'e' || letter == 'E' || letter == 'i'
        || letter == 'I' || letter == 'o' || letter == 'O' || letter == 'u' || letter == 'U')
        {
            // Console.WriteLine("first char of the word is a vowel");
            string s1 = sb.Remove(0, 1).ToString();
            sb.Insert(s1.Length, letter);
            sb.Insert(sb.Length, che);
        }
        else
        {
            // Console.WriteLine("first char of a word is a consonant");
            sb.Insert(s.Length, che);
        }

        if (s.Length % 2 == 0)
        {
            // Console.WriteLine("the word has even numbers of letters");
            // sb.Insert(s.Length, "e");
            sb.Insert(sb.Length, "e");
        }
        //Console.WriteLine(firstchar);
        int currentWordLength = s.Length;

        strFinal += sb + " ";
    }

    Console.WriteLine(strFinal);
    Console.ReadKey();

我喜欢这个。我会尝试一下,因为我刚学习StringBuilder。 - grozdeto
@grozdeto 我在我的端上运行和测试了。肯定会很好地工作。输出与您的需求相匹配。如果您从这个答案中得到帮助,请不要忘记接受它。谢谢。 - Ali Azam
谢谢您的帮助,但它并不适用于所有例子。对于输入: 他已经不再是个年轻人了 输出为: Heeche sieche noeche springeche chickenche nymoreache正确的输出应该是: Hechee sichee nochee springchee chickenche nymoreache - grozdeto
@grozdeto 嘿兄弟,IF条件中有一个愚蠢的错误(与偶数计算有关)。应该是 sb.Length 而不是 s.Length。我已经更正了答案,请再次检查。 - Ali Azam
@grozdeto 正确的代码应该是 sb.Insert(sb.Length, "e"); - Ali Azam

1
使用明显的扩展方法:
public static class ExtensionMethods {
    // ***
    // *** int Extensions
    // ***
    public static bool IsEven(this int n) => n % 2 == 0;

    // ***
    // *** String Extensions
    // ***
    public static bool StartsWithOneOf(this string s, HashSet<char> starts) => starts.Contains(s[0]);
    public static string Join(this IEnumerable<string> strings, string sep) => String.Join(sep, strings);
}

您可以使用LINQ处理规则:
var vowels = "aeiouAEIOU".ToHashSet();

var ans = src.Split(' ')
             .Select(w => (w.StartsWithOneOf(vowels) ? w.Substring(1)+w[0] : w)+"che"+(w.Length.IsEven() ? "e" : ""))
             .Join(" ");

1

首先,我建议您将翻译代码更改为作用于单词而不是整个句子的函数。因此,在foreach (string s in output)中的代码应移动到另一个仅对该字符串进行操作的函数中。不要尝试操纵传递的字符串,根据您列出的逻辑创建一个新的字符串。一旦创建了翻译后的字符串,请将其返回给调用者。然后,调用者会从每个返回的翻译中重构句子。


0

if语句结束之前,您不应更改您的单词。您需要测试所有条件并将结果保存在其他变量中,最后对单词进行更改:

foreach (string s in output)
    {
        letter = char.ToLower(s[0]);
        bool isVowel = false;
        bool isEven = false;

        if (letter == 'a' || letter == 'e' || letter == 'i'
         || letter == 'o' || letter == 'u')
        {
           isVowel = true;
        }            

        if (s.Length % 2 == 0)
        {
            isEven = true;
        }

        //Now you can change the word
        if (isVowel)
        {
            //Do What you want
        }

        if (isEven)
        {
            //Do What you want
        }

        //Console.WriteLine(firstchar);
        int currentWordLength = s.Length;

    }

-1
我建议将逻辑分解为特定的单元,以便您可以编写测试。
    static void Main(string[] args)
    {
        var input = Console.ReadLine();
        var inputs = input.Split(' ');
        var sentence = string.Join(" ", inputs.Select(ConvertWord));
        Console.Write(sentence);
        Console.Read();
    }

    internal static string ConvertWord(string input)
    {
        const string che = "che";

        var vowels = new List<string>
        {
            "a","A", "e", "E", "i", "I", "o", "O", "u", "U"
        };

        var firstChar = input.First();

        var startsWithVowel = vowels.SingleOrDefault(a => a.Equals(firstChar));

        string rule2String, output;

        if (string.IsNullOrEmpty(startsWithVowel))
        {
            output = input + che;
        }

        else
        {
            output = input.Substring(1) + startsWithVowel + che;
        }

        rule2String = IsLengthEven(input)
            ? output + "e"
            : output
        ;

        return rule2String;
    }

    internal static bool IsLengthEven(string input)
    {
        return input.Length % 2 == 0;
    }

希望这有所帮助! 附注:我还没有涵盖边缘情况。

在你的代码中,startsWithVowel 将始终为 null。另外,为什么你要让元音测试变得如此不必要地复杂呢?为什么不想使用简单的字符数组/列表与 Contains 方法结合使用呢? - user2819245

-1
我建议使用带有 String.Format 的 Linq 的 String.Join。然后解决方案就很容易:
    private String convertSentence() {
        var sentence = "Hello there Amy";
        var vowels = "aeiou";
        var che = "che";

        return String.Join(" ", (
                from s in sentence.Split(' ')
                let moveFirstToEnd = vowels.Contains(s.ToLower()[0]) && s.Length > 1 
                select String.Format("{0}{1}{2}{3}"
                    , moveFirstToEnd ? s.Substring(1) : s
                    , moveFirstToEnd ? s.Substring(0, 1) : String.Empty
                    , che
                    , s.Length % 2 == 0 ? "e" : String.Empty
                )
            )
        );
    }

从问题中可以很清楚地看出,这是一些学校作业/任务或课程作业,旨在学习编程基础知识。虽然我相信你的答案在技术上是可行的,但它完全偏离了问题的本意,因为它使用了一个相对复杂的Linq查询,远远超出了所要求的作业范围。 - user2819245
为什么要给一个好的答案投反对票?即使它是作业,其他人也会使用 Stackoverflow 来寻找答案。不只是那个提问者看这个页面。 - Egbert

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接