把单词倒过来
本文关键字:倒过来 单词 | 更新日期: 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 ,
}) ;
}