把单词倒过来

本文关键字:倒过来 单词 | 更新日期: 2023-09-27 18:12:18

这就是问题所在:

"编写一个程序,在不改变标点和空格的情况下将给定句子中的单词颠倒过来。例如:"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();
    }

我的问题是,我解决的方式是特定于给出的例子。如果有其他分隔符,代码将无法正常工作。那么,我如何推广该算法,使用给定的提示来处理任何分隔符?!

把单词倒过来

你的Method/Function的一个更短的版本看起来像这样:

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

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

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

string[] words = str.Split('.', ' ');

你只是'。'和' ',非常简单,您需要扩展此列表以涵盖所有可能的标点符号(如!,?等)

"以获得文本中的单词和,然后按字母分割以获得文本的标点符号。"

现在对原始字符串做同样的事情,但是使用所有可能的字母字符作为分隔符,而不是使用标点符号。这将取出没有空格或字母的标点符号。

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

您可以使用正则表达式

来解决这个问题

它看起来像

('w+|[^'w])

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

我认为关键在于如何定义"word"。像mother-in-law这样的东西是一个单词,还是三个单词,用连字符分隔。That's呢?

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

首先,让我们定义一个自定义数据类型来表示我们的标记:一个带有关联类型(在我们的例子中是'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 )
{
  StringBuilder sb = new StringBuilder() ;
  int i = 0 ;
  while ( i < s.Length )
  {
    // gobble and return a punctuation token, if there is one.
    sb.Length = 0 ;
    while ( i < s.Length && !char.IsLetterOrDigit(s[i]) )
    {
      sb.Append(s[i++]) ;
    }
    if ( sb.Length > 0 ) yield return new Token{ Type = TokenType.NonWord , Text = sb.ToString() , } ;
    // gobble the next word and return it.
    sb.Length = 0 ;
    while ( i < s.Length && char.IsLetterOrDigit( s[i] ) )
    {
      sb.Append( s[i++] ) ;
    }
    if ( sb.Length > 0 ) yield return new Token{ Type = TokenType.Word , Text = sb.ToString() , } ;
  }
}

之后,一切都很简单:

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 ,
         }) ;
}