C# 颠倒词语

C# 颠倒词语,c#,C#,问题是: 编写一个程序,在不改变标点和空格的情况下,将给定句子中的单词颠倒过来。例如:C不是C++,PHP不是Delphi,Delphi不是PHP,C++不是C. 这是一个提示: 另一个有趣的方法是通过单词之间的标点符号分割输入文本,以便只得到文本中的单词,然后通过字母分割得到文本中的标点符号。因此,给定单词列表和单词之间的标点符号列表,您可以轻松地反转单词,保留标点符号 这是我目前的代码: public static string ReverseWords(string str) {

问题是:

编写一个程序,在不改变标点和空格的情况下,将给定句子中的单词颠倒过来。例如:C不是C++,PHP不是Delphi,Delphi不是PHP,C++不是C.

这是一个提示: 另一个有趣的方法是通过单词之间的标点符号分割输入文本,以便只得到文本中的单词,然后通过字母分割得到文本中的标点符号。因此,给定单词列表和单词之间的标点符号列表,您可以轻松地反转单词,保留标点符号

这是我目前的代码:

public static string ReverseWords(string str)
    {
        StringBuilder answer = new StringBuilder();
        string[] words = str.Split('.', ' ');
        char[] x = str.ToCharArray();

        string[] punctuation = str.Split(str.ToCharArray());

        for(int position = words.Length - 1; position >= 0; position--)
        {
            answer.Append(words[position]);
            answer.Append(' ');
        }

        return answer.ToString();
    }
我的问题是,我解决问题的方法与给出的示例是特定的。如果存在其他分隔符,则代码无法正常工作。
那么,如何使用给定的提示将算法推广到使用任何分隔符

另一个有趣的方法是通过单词之间的标点符号分割输入文本

您在这里这样做了,只需要扩展分隔符以覆盖其他标点符号

string[] words = str.Split('.', ' ');
您只有“.”和“”,非常简单,您需要扩展此列表以涵盖所有可能的标点符号,例如?,等等

为了得到文本中的单词,然后用字母分割得到文本的标点符号

现在对原始字符串执行相同的操作,但是使用所有可能的字母字符作为分隔符,而不是使用标点符号。这将拉出没有空格或字母的标点符号


棘手的部分是在新句子中把那些讨厌的标点符号放在哪里。我的解决方案可能不是最优雅的解决方案,但我会计算标记前的n个空格,并将标记放在新句子中的n+1单词之后。请记住,这无论如何都不能保证语法正确:

您可以用正则表达式解决这个问题

看起来像

(\w+|[^\w])

匹配组将是单词或标点符号,然后您可以反转匹配。

方法/函数的简短版本如下所示:

public static string ReverseWords(string str)
{       
   return String.Join(" ", str.Split('.', ' ').Reverse()).ToString();
}

我认为,这里的诀窍在于如何定义这个词。有点像岳母,一个单词,或三个单词,用连字符分隔。那是什么

为了论证的目的,我将单词定义为字母和数字的序列

首先,让我们定义一个自定义数据类型来表示我们的标记:一个文本块,在我们的例子中有一个关联的类型“word”或“non-word”:

public enum TokenType
{
  Word    = 1 ,
  NonWord = 2 ,
}

public class Token
{

  public TokenType Type { get ; set ; }
  public string    Text { get ; set ; }

  // This helps in viewing instances in the debugger
  public override string ToString()
  {
    return string.Format( "{0}:{1}" , Type,Text ) ;
  }

}
一旦我们有了这些,我们需要一个标记器来将源文本分割成一系列标记:

进一步编辑以注意:如果您想使用正则表达式,可以使用如下内容作为标记器:

static IEnumerable<Token> Tokenize( string s )
{
  Regex rx = new Regex( @"(?<word>\w+)|(?<nonword>\W+)" , RegexOptions.IgnoreCase ) ;
  return rx
         .Matches( s )
         .Cast<Match>()
         .Select( m => new Token {
           Type = m.Groups["word"].Success ? TokenType.Word         : TokenType.NonWord         ,
           Text = m.Groups["word"].Success ? m.Groups["word"].Value : m.Groups["nonword"].Value ,
         }) ;
}

实际上,这是一个可怕的暗示。从头到尾读取字符串、累积单词、反转并写入字符串生成器要容易得多。允许使用Regex吗?@zerkms-Ya这种方式也包括在内。因此,为什么这个提示从另一个开始。但由于我能够实现我认为:,我选择了这个更有趣的方法。我喜欢使用字符串方法,因为我想熟悉它们。@ToddRichardson没有。只是因为我还没有学习正则表达式:@Mustafa:Ya这种方法也包括在内。它不是-你的解决方案意味着它是一个作为分隔符的空间。我的-只是一个接一个地读字符,没有任何假设。这对我来说很美。它适用于任何分隔符。Thanx@Mustafa:很高兴它对你有用。祝你快乐,愿上帝保佑。
static int Main( string[] argv )
{
  string src = "The quick brown fox, who was named Fred, jumped over a lazy Dog (named Suzy) chasing a squirrel." ;
  List<Token> tokens = new List<Token>( Tokenize( src ) ) ;

  int i = 0 ;
  int j = tokens.Count - 1 ;

  // loop, reversing words as we go.
  while ( i < j )
  {
    Token left  = tokens[i] ;
    Token right = tokens[j] ;

    if ( left.Type  != TokenType.Word ) { ++i ; continue ; }
    if ( right.Type != TokenType.Word ) { --j ; continue ; }

    // at this point, we have two words: swap them
    tokens[i++] = right     ;
    tokens[j--] = left      ;

  }

  // Finally, put everything back together
  string rev = tokens
               .Aggregate( new StringBuilder() , (b,t) => b.Append(t.Text) )
               .ToString()
               ;

  // Et, Voila!
  Console.WriteLine( "src: {0}" , src ) ;
  Console.WriteLine( "rev: {0}" , rev ) ;

  return 0 ;
}
src: The quick brown fox, who was named Fred, jumped over a lazy Dog (named Suzy) chasing a squirrel.
rev: squirrel a chasing Suzy, named Dog lazy a, over jumped Fred named was (who fox) brown quick The.
static IEnumerable<Token> Tokenize( string s )
{
  Regex rx = new Regex( @"(?<word>\w+)|(?<nonword>\W+)" , RegexOptions.IgnoreCase ) ;
  return rx
         .Matches( s )
         .Cast<Match>()
         .Select( m => new Token {
           Type = m.Groups["word"].Success ? TokenType.Word         : TokenType.NonWord         ,
           Text = m.Groups["word"].Success ? m.Groups["word"].Value : m.Groups["nonword"].Value ,
         }) ;
}