这就是问题:
“编写一个程序,在不改变标点符号和空格的情况下反转给定句子中的单词。例如:”C#不是C ++而PHP不是Delphi“à”Delphi不是PHP而C ++不是C#“。” / p>
这是提示:
“另一个有趣的方法是通过单词之间的标点符号来分割输入文本,以便只获取文本的单词,然后用字母分割以获得文本的标点符号。因此,给出一个单词列表和一个它们之间的标点符号列表,您可以轻松地反转单词,保留标点符号。“
到目前为止,这是我的代码:
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();
}
我的问题是我解决的方式特定于给出的例子。如果还有其他分隔符,则代码无法正常工作。 那么如何使用给定的提示推广算法以使用任何分隔符?!
答案 0 :(得分:1)
Method/Function
的更短版本看起来像这样:
public static string ReverseWords(string str)
{
return String.Join(" ", str.Split('.', ' ').Reverse()).ToString();
}
答案 1 :(得分:0)
“另一个有趣的方法是通过单词之间的标点符号拆分输入文字”
你在这里做到了,只需要扩展分隔符以覆盖其他标点符号
string[] words = str.Split('.', ' ');
你刚刚'。'并且'',非常简单,您需要扩展此列表以涵盖所有可能的标点符号(例如!,?等)
“为了得到文本的单词而然后用字母分割以获得文本的标点符号。”
现在对原始字符串执行相同操作,但使用所有可能的字母字符作为分隔符,而不是使用标点符号。这将删除没有空格或字母的标点符号。
棘手的部分是在新句子中放置那些讨厌的标点符号。我的解决方案可能不是最优雅的解决方案,但我会在标记之前计算n个空格,并将标记放在新句子中的n + 1个单词之后。请记住,这绝不会保证良好的语法:)
答案 2 :(得分:0)
您可以使用正则表达式解决此问题
看起来像
(\w+|[^\w])
匹配组将是单词或标点符号,然后您可以反转匹配。
答案 3 :(得分:0)
我认为,这里的诀窍在于你如何定义“单词”。像mother-in-law
这样的单词,或3个单词,用连字符分隔。 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 ) ;
}
}
完成后,我们需要 tokenizer 将源文本拆分为一系列令牌:
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 ,
}) ;
}