[英]Reversing the word order in a string in place
I'm trying to reverse the order of words in a sentence in place, eg: 我试图在一个句子中改变单词的顺序,例如:
This sentences words are reversed.
这句话是相反的。
becomes 变
reversed.
逆转。 are words sentences This
是单词句子这个
This is what I have so far, which almost works: I use the strrev function to reverse the string, and then the inprev function to send each word to the strrev function individually, to reverse them back to the original orientation, but in reversed order. 这是我到目前为止,它几乎可以工作:我使用strrev函数来反转字符串,然后使用inprev函数将每个单词单独发送到strrev函数,将它们反转回原始方向,但顺序相反。 Sending a pointer for the start and end of the strrev function might seem a bit silly, but it allows the same function to be used in inprev(), sending off a pointer to the start and end of individual words.
为strrev函数的开始和结束发送指针可能看起来有点傻,但它允许在inprev()中使用相同的函数,发送指向单个单词的开头和结尾的指针。
#include <stdio.h>
#include <string.h>
void strrev(char * start, char * end);
void inprev(char * start);
int main(void)
{
char str[] = "Foobar my friends, foobar";
char * end = (str + strlen(str) -1);
puts(str);
strrev(str, end);
puts(str);
inprev(str);
puts(str);
return 0;
}
void strrev(char * start, char * end)
{
char temp;
while (end > start)
{
temp = *start;
*start = *end;
*end = temp;
start++;
end--;
}
}
void inprev(char * start)
{
char * first = start;
char * spcpnt = start;
while (*spcpnt)
{
while (*spcpnt != ' ' && *spcpnt)
spcpnt++;
strrev(start, spcpnt-1); // removing the -1 sends the space on the
start = spcpnt++; // other side to be reversed, doesn't stop
// the problem.
}
}
Here is the output: 这是输出:
Foobar my friends, foobar
Foobar我的朋友,foobar
raboof ,sdneirf ym rabooF
raboof,sdneirf ym rabooF
foobarfriends, my Foobar
foobarfriends,我的Foobar
The problem is that the lack of a final space at the end of the final word means that a space is missing between that word and the preceeding one in the final string, and instead gets thrown onto the end of the last word, which was the first word in the original string. 问题是在最后一个单词的末尾缺少最后一个空格意味着该单词和最后一个单词中的前一个单词之间缺少一个空格,而是被抛到最后一个单词的末尾,这就是原始字符串中的第一个单词。 Sending off the space on the other side of the word only moves the problem elsewhere.
发送单词另一侧的空格只会将问题移到其他地方。 Can anyone see a solution?
有谁能看到解决方案?
You just need to move the start
pointer in the inprev
function to skip the space between words. 您只需要在
inprev
函数中移动start
指针以跳过单词之间的空格。 As this appears to be homework (correct me if I'm wrong) I'll just say that all you need to do is move the location of one operator. 因为这似乎是家庭作业(纠正我,如果我错了)我只会说你需要做的就是移动一个操作员的位置。
But, this produces a problem, namely, the inprev
performs a buffer overrun because the search isn't terminated properly. 但是,这会产生一个问题,即
inprev
执行缓冲区溢出,因为搜索未正确终止。 A better way to do it is: 更好的方法是:
while not end of string
search for start of word
start = start of word
search for end of word
strrev (start, end)
and that will take care of multiple spaces too. 这也将照顾多个空间。 Also, U+0020 (ASCII 32, a space) is not the only white space character.
此外,U + 0020(ASCII 32,空格)不是唯一的空格字符。 There are standard library functions that test characters.
有标准的库函数来测试字符。 They are in <ctype.h> and start with
is...
, eg isspace
. 它们位于<ctype.h>中,以
is...
开头,例如isspace
。
Sometimes things get easier if you don't use pointers but offsets. 如果你不使用指针而是偏移,有时事情变得更容易。 The strspn() and strcspn() library functions more or less force you to use offsets, and deal with the end-of-string condition quite nicely.
strspn()和strcspn()函数函数或多或少地强制你使用偏移量,并且很好地处理字符串结束条件。
#include <stdio.h>
#include <string.h>
size_t revword(char *str);
void revmem(void *ptr, size_t len);
size_t revword(char *str) {
size_t pos,len;
for (pos=len=0; str[pos]; pos += len) {
len = strspn( str+pos, " \t\n\r");
if (len) continue;
len = strcspn( str+pos, " \t\n\r");
if (!len) continue;
revmem( str+pos, len );
}
revmem( str, pos );
return len;
}
void revmem(void *ptr, size_t len)
{
size_t idx;
char *str = (char*) ptr;
if (len-- < 2) return;
for (idx = 0; idx < len; idx++,len--) {
char tmp = str[idx];
str[idx] = str[len];
str[len] = tmp;
}
}
int main (int argc, char **argv)
{
if (!argv[1]) return 0;
revword(argv[1] );
printf("'%s'\n", argv[1] );
return 0;
}
The following algorithm is in-place and runs in 2 steps. 以下算法就地并以两个步骤运行。 First it reverses the entire string.
首先它反转整个字符串。 Then it reverses each word.
然后它反转每个单词。
#include <stdio.h>
void reverse(char *str, int len)
{
char *p = str;
char *e = str + len - 1;
while (p != e) {
*p ^= *e ^= *p ^= *e;
p++;
e--;
}
}
void reverse_words(char *str)
{
char *p;
// First, reverse the entire string
reverse(str, strlen(str));
// Then, reverse each word
p = str;
while (*p) {
char *e = p;
while (*e != ' ' && *e != '\0') {
e++;
}
reverse(p, e - p);
printf("%.*s%c", e - p, p, *e);
if (*e == '\0')
break;
else
p = e + 1;
}
}
int main(void) {
char buf[] = "Bob likes Alice";
reverse_words(buf);
return 0;
}
void reverse_str(char* const p, int i, int j) // helper to reverse string p from index i to j
{
char t;
for(; i < j ; i++, j--)
t=p[i], p[i]=p[j], p[j]=t;
}
void reverse_word_order(char* const p) // reverse order of words in string p
{
int i, j, len = strlen(p); // use i, j for start, end indices of each word
reverse_str(p, 0, len-1); // first reverse the whole string p
for(i = j = 0; i < len; i = j) // now reverse chars in each word of string p
{
for(; p[i] && isspace(p[i]);) // advance i to word begin
i++;
for(j = i; p[j] && !isspace(p[j]);) // advance j to past word end
j++;
reverse_str(p, i, j-1); // reverse chars in word between i, j-1
}
}
Figured out a solution; 想出一个解决方案; here is my revised function that works properly.
这是我修改后的功能正常工作。
void inprev(char * str)
{
_Bool inword = 0;
char * wordend;
char * wordstart;
while(*str)
{
if(!isspace(*str) && (inword == 0))
{
wordstart = str;
inword = 1;
}
else if (isspace(*str) && (inword == 1))
{
wordend = str-1;
inword = 0;
strrev(wordstart, wordend);
}
str++;
}
if (*str == '\0')
strrev(wordstart, str-1);
}
char * wordend is uneccessary as you can just pass str-1 to the strrev function, but it makes it a bit more clear what's happening. char * wordend是不必要的,因为你可以将str-1传递给strrev函数,但它会更清楚地说明发生了什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.