Как отменить предложение в Си и Perl - PullRequest
1 голос
/ 26 мая 2011

Если предложение «меня зовут Джек», то вывод должен быть «Джек зовут мой».

Я создал программу, используя strtok() для разделения слов, а затем поместил их в стек, высовывая их и объединяя.

Есть ли другой, более эффективный способ, чем этот?Это проще сделать в Perl?

Ответы [ 10 ]

8 голосов
/ 26 мая 2011

Будет ли это более эффективным или нет, вы сможете протестировать, но в Perl вы можете сделать что-то вроде:

my $reversed = join( " ", reverse( split( / /, $string ) ) );
5 голосов
/ 26 мая 2011

Perl делает этот вид манипулирования текстом очень простым, вы даже можете легко проверить это на оболочке:

echo "run as fast as you can" | perl -lne 'print join $",reverse split /\W+/'

или:

echo "all your bases are belong to us" | perl -lne '@a=reverse /\w+/g;print "@a"'
4 голосов
/ 26 мая 2011

Стратегия для C может быть такой:

1) Поменять местами символы строки.Это приводит к тому, что слова являются правильной общей позицией, хотя и в обратном направлении.
2) Обратные символы каждого слова в строке.

Нам понадобится одна функция для обращения символов в буфере:

/*
 * Reverse characters in a buffer.
 * 
 * If provided "My name is Jack", modifies the input to become
 * "kcaJ si eman yM".
 */
void reverse_chars(char * buf, int cch_len)
{
    char * front = buf, *back = buf + cch_len - 1;

    while (front < back)
    {
        char tmp = *front;
        *front = *back;
        *back = tmp;
        front ++;
        back --;
    }
}

Для разбивки входного буфера на слова - функция, которая возвращает количество непробельных символов в буфере.(strtok () изменяет буфер и его сложнее использовать на месте)

int word_len(char *input)
{
    char * p = input;

    while (*p && !isspace(*p))
        p++;

    return p - input;
}

Наконец, нам понадобится функция, которая использует этих двух помощников для реализации стратегии, описанной в первом абзаце.

/*
 * Reverse words in a buffer.
 *
 * Given the input "My name is Jack", modifies the input to become
 * "Jack is name My"
 */
void reverse_words(char *input)
{
     int cch_len = strlen(input);

     /* Part 1: Reverse the string characters. */
     reverse_chars(input, cch_len);

     char * p = input;

     /* Part 2: Loop over one word at a time. */
     while (*p)
     {
         /* Skip leading spaces */
         while (*p && isspace(*p))
             p++;

         if (*p)
         {
             /* Advance one complete word. */
             int cch_word = word_len(p);
             reverse_chars(p, cch_word);
             p += cch_word;
         }
     }
}
2 голосов
/ 27 мая 2011

Вот идея C, которая использует небольшую рекурсию, чтобы сделать укладку для вас:



void rev(char * x){
  char * p;
  if(p = strchr(x, ' ')){
    rev(p+1);
    printf("%.*s ", p-x, x);
  }
  else{
    printf("%s ", x);
  }

}

2 голосов
/ 27 мая 2011

Немного веселья с небольшой помощью специальных переменных regexp и perl:)

$_ = "My name is Jack";
unshift @_, "$1 " while /(\w+)/g;
print @_;

EDIT

И убийца (сейчас):

$,=' ';print reverse /\w+/g;

Небольшое объяснение: $, это специальная переменная для разделителя вывода на печать. Конечно, вы можете сделать это более коротким способом без этой специальной переменной:

print reverse /\w+ ?/g;

но результат может быть не таким удовлетворительным, как в примере выше.

2 голосов
/ 26 мая 2011

Вы получили пару версий на C, но они кажутся мне более многословными, чем, вероятно, действительно необходимо. Если нет причин поступить иначе, я бы рассмотрел что-то вроде этого:

#define MAX 32

char *words[MAX];
char word[256];
int pos = 0;

for (pos=0; pos<MAX && scanf("%255s", word); pos++)
    words[pos] = strdup(word);

while (--pos >= 0)
  printf("%s ", words[pos]);  

Одним из возможных «промежуточных» уровней между C и Perl будет C ++:

std::istringstream input("My name is Jack");
std::vector<std::string> words((std::istream_iterator<std::string>(input)),
                               std::istream_iterator<std::string>());

std::copy(words.rbegin(), words.rend(), 
          std::ostream_iterator<std::string>(std::cout, " "));
1 голос
/ 26 мая 2011

Вероятно, это гораздо проще сделать в Perl, но ...

char *strrtok(char *str, const char *delim)
{
    int i, j;

    for (i = strlen(str) - 1; i > 0; i--)
    {
        // Sets the furthest set of contiguous delimiters to null characters
        if (strchr(delim, str[i]))
        {
            j = i + 1;

            while (strchr(delim, str[i]) && i >= 0)
            {
                str[i] = '\0';
                i--;
            }

            return &(str[j]);
        }
    }

    return str;
}

Это должно работать аналогично strtok() в обратном порядке, но вы продолжаете скорее передавать указатель на исходную строкучем пропуск NULL после первого звонка.Кроме того, вы должны получить пустые строки для начального и конечного случаев.

1 голос
/ 26 мая 2011

Использование reverse:

my @words = split / /, $sentence;
my $newSentence = join(' ', reverse @words);
0 голосов
/ 26 мая 2011

C версия:

#include <string.h>
int main()
{
char s[] = "My name is Jack";
char t[100];
int i = 0, j = 0, k = 0;

for(i = strlen(s) - 1 ; i >= 0 ;i--)
{
    if(s[i] == ' ' || i == 0)
    {
        j = i == 0 ?  i : i + 1;
        for(j = j; s[j] != '\0'; j++) t[k++] = s[j];
        t[k++] = ' ';
        s[i] = '\0';
    }
}
t[k] = '\0';
printf("%s\n", t);
return 0;
}
0 голосов
/ 26 мая 2011

C пример

char * srtrev (char * str) {

       int l = strlen(str);
       char * rev;
       while(l != 0)
       {
         rev += str[ --l];
       }
        return rev;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...