如何反转字符串每个单词中的字母

时间:2016-07-28 11:28:48

标签: c string

如何反转字符串的单词,但只能反转字符和数字。例如:

this is the start! 
siht si eht trats!

我已经编写了这段代码,但它反转了所有内容(也就是'!'); 我得到的输出是:

siht si eht !trats

代码:

#include<stdio.h>
void reverse(char *begin, char *end);
    void reverseWords(char *s)
        {

    char *word_begin = s;
    char *temp = s;
    while(isalnum(*temp) || *temp )
         {


            temp++;


    if (*temp == '\0')
            {    
              reverse(word_begin, temp-1);
            }
            else if(*temp == ' ')
            {
            reverse(word_begin, temp-1);
            word_begin = temp+1;
        }
  }
}
    void reverse(char *begin, char *end)
{

    char temp;
    while (begin < end)
    {
        temp = *begin;
        *begin++ = *end;
        *end-- = temp;
    }

}
    int main()
{

    char s[50];
    scanf("%[^\n]",&s);

    char *temp = s;
    reverseWords(s);
    printf("%s", s);

    getchar();

    return 0;
}

2 个答案:

答案 0 :(得分:1)

您拥有的reverse()功能是您需要的有用工具。许多传统版本依赖于仅传递文本的开头以进行反转,但是出于您的目的,将指针传递给要反转的范围的第一个和最后一个字符非常简洁。除了琐事之外我一直用它。我创建它static因为我创建了每个函数(除了main()static,除非有一个声明它的标题并且它被多个源文件使用 - 只有一个源文件这段代码。

然后,您需要做的就是确定文本中每个单词的开头和结尾。这通常最好用嵌套循环完成 - 一个在'未到达输入字符串的末尾',然后在其中,跳过非字母(非单词)字符,记录单词的开头,跳过字母(单词)字符,在开始和结束之间反转单词,并重复外循环。

这导致了这样的代码。

#include <ctype.h>
#include <stdio.h>
#include <string.h>

static void reverse(char *begin, char *end)
{
    while (begin < end)
    {
        char temp = *begin;
        *begin++ = *end;
        *end-- = temp;
    }
}

static void reverseWords(char *s)
{
    while (*s != '\0')
    {
        while (*s != '\0' && !isalnum((unsigned char)*s))
            s++;
        char *word = s;
        while (isalnum((unsigned char)*s))
            s++;
        reverse(word, s-1);
    }
}

int main(void)
{
    char s[1024];
    while (fgets(s, sizeof(s), stdin) != 0)
    {
        s[strcspn(s, "\n")] = '\0';
        printf("In:  [%s]\n", s);
        reverseWords(s);
        printf("Out: [%s]\n", s);
    }

    return 0;
}

(unsigned char)强制转换是在普通char为签名类型的机器上正确处理单字节代码集(如ISO 8859-15)中的重音字符所必需的。

示例输出:

this is the start!
In:  [this is the start!]
Out: [siht si eht trats!]
and this isn't the end.
In:  [and this isn't the end.]
Out: [dna siht nsi't eht dne.]
   Neither leading blanks nor trailing ones interfere   
In:  [   Neither leading blanks nor trailing ones interfere   ]
Out: [   rehtieN gnidael sknalb ron gniliart seno erefretni   ]
 Lots..of=intermediate=punctuation@interruptions.com^give&no&&&trouble  
In:  [ Lots..of=intermediate=punctuation@interruptions.com^give&no&&&trouble  ]
Out: [ stoL..fo=etaidemretni=noitautcnup@snoitpurretni.moc^evig&on&&&elbuort  ]

请注意,如果您决定将撇号计为单词的一部分(因此“doesn't”映射到"t'nseod"而不是"nseod't",如上面的代码所示,您只需需要修复循环中的条件。那时,我可能会创建一个static inline函数来完成这项工作:

static inline int is_word_char(int c)
{
     return isalpha(c) || c == '\'';
}

请注意,<ctype.h>会保留以is(和to)开头的单词,后跟小写字母;使用名称is_word_char()可以避免使用此类保留字。此外,该函数被定义为采用int,就像<ctype.h>中的函数一样,以简单一致。

反向词功能变为:

static void reverseWords(char *s)
{
    while (*s != '\0')
    {
        while (*s != '\0' && !is_word_char((unsigned char)*s))
            s++;
        char *word = s;
        while (is_word_char((unsigned char)*s))
            s++;
        reverse(word, s-1);
    }
}

甚至可以通过传递一个合适的指向函数来概括reverseWords()

static void reverseWords(char *s, int (*is_word)(int))
{
    while (*s != '\0')
    {
        while (*s != '\0' && !is_word((unsigned char)*s))
            s++;
        char *word = s;
        while (is_word((unsigned char)*s))
            s++;
        reverse(word, s-1);
    }
}

现在你要从inline删除is_word_char(),因为你需要一个函数指针的实际函数,然后你可以使用:

reverseWords(s, isalnum);
reverseWords(s, is_word_char);

这种泛化程度的缺点是实际函数调用对每个字符进行分类的成本,失去了内联分类器函数的可能性。

侧面调试

我用reverseWords()函数输入了这个答案的初步版本,如下所示:

static void reverseWords(char *s)
{
    while (*s != '\0')
    {
        while (!isalnum((unsigned char)*s))
            s++;
        char *word = s;
        while (isalnum((unsigned char)*s))
            s++;
        reverse(word, s-1);
    }
}

区别在于!isalnum循环 - 那里没有检查空字节。然后我意识到代码必须跳过空字节。像这样检测:

static void reverseWords(char *s)
{
    while (*s != '\0')
    {
        while (/**s != '\0' &&*/ !isalnum((unsigned char)*s))
        {
            printf("= %d", *s);
            s++;
        }
        putchar('\n');
        char *word = s;
        while (isalnum((unsigned char)*s))
            s++;
        reverse(word, s-1);
    }
}

然后运行它“这是开始!”产出太多产量:

this is the start!
In:  [this is the start!]

= 32
= 32
= 32
= 33= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0= -49= 0= -24
= -48= 41= 96
= -122= 46
= -1= 127= 0= 0= -120= -124= 46
= -1= 127= 0= 0
…many lines omitted…
= -1= 127= 0= 0= -118= -113= 46
= -1= 127= 0= 0= -65= -113= 46
= -1= 127= 0= 0= 0= 0= 0= 0= 0= 0= 0= 0
= 95
= 61= 46= 47
Out: [siht si eht trats!]

输出看起来很清醒 - 但代码却在各种不应该去的地方戳过。

只要空字节未通过“是字符”测试,修改后的代码就是安全的。

答案 1 :(得分:0)

我会使用ASCII表和if函数来说: &#39;只反转/移动数组的最后一个元素(字母){字} if ASCII字符在65-90(大写字母),97-122(小写)和48-57之间(小数)&#39 ;.

如果你要在单词中加入符号,这可能会让你更加棘手,但我假设你不会因为你的例子永远不会有这样的符号!在一个单词的中间。

示例:

if ((int) s[i] == 33)

[特别是数组s中的字符,位置i碰巧是一个! (由ASCII表中的小数33表示。)]