8
votes

Inverser le mot ordre dans une chaîne en place

J'essaie d'inverser l'ordre des mots dans une phrase en place, par exemple:

Ce mots de phrases sont inversés.

devient

inversé. sont des phrases de mots ce

C'est ce que j'ai jusqu'à présent, ce qui fonctionne presque: J'utilise la fonction Strrev pour inverser la chaîne, puis la fonction INPREV pour envoyer chaque mot à la fonction Strrev individuellement, pour les inverser à l'orientation d'origine, mais dans l'ordre inversé. L'envoi d'un pointeur pour le début et la fin de la fonction Strrev peut sembler un peu stupide, mais elle permet d'utiliser la même fonction dans INPREV (), d'envoyer un pointeur au début et à la fin des mots individuels. < Pré> xxx

Voici la sortie:

foobar mes amis, foobar

Raboof, SDNeirf YM Raboof

foobarfriends, mon foobar

Le problème est que l'absence d'un espace final à la fin du mot final signifie qu'un espace est manquant entre ce mot et le précédent celui de la chaîne finale, et devient plutôt jeté sur la fin de Le dernier mot, qui était le premier mot de la chaîne d'origine. L'envoi de l'espace de l'autre côté du mot ne fait que déplacer le problème ailleurs. Quelqu'un peut-il voir une solution?


5 commentaires

Que êtes-vous censé faire lorsque vous rencontrez des espaces x? Appartiennent-ils au mot avant ou après?


+1 Bon problème :). Si j'aurai un peu de temps, je vais fournir une solution


Je suppose que vous ne voulez pas trop faire la première lettre une grosse, alors que votre exemple montre ...


@Redx n'a pas pensé à cela, je vais avoir un autre regard sur mon algorithme et essayer de penser à quelque chose


@imacake correct, typo. Merci.


5 Réponses :


6
votes

Il vous suffit de déplacer le pointeur Démarrer dans la fonction inPrev pour ignorer l'espace entre les mots. Comme cela semble être des devoirs (corrigez-moi si je me trompe), je vais simplement dire que tout ce que vous avez à faire est de déplacer l'emplacement d'un opérateur.

Mais, cela produit un problème, à savoir le inPrev effectue une dépassement de mémoire tampon car la recherche n'est pas terminée correctement. Une meilleure façon de le faire est la suivante: xxx

et qui prendra soin de plusieurs espaces aussi. De plus, U + 0020 (ASCII 32, un espace) n'est pas le seul caractère d'espace blanc. Il existe des fonctions de bibliothèque standard qui testent des caractères. Ils sont dans et commencent par est ... , par ex. ISSPACE .


6 commentaires

Merci! Question initiale mise à jour avec mon algorithme fixe. Pas de devoirs BTW, l'a vu dans une interview d'emploi Question Prep et pensé que j'aurais une fissure à l'amusement.


@Matt s'il vous plaît ne corrigez pas le code d'origine dans la question! Cela rend la question inutile pour quiconque le lit à l'avenir. Je vais retourner cette modification.


@Matt: Pour ajouter au commentaire de Razlebe, vous pouvez publier le code mis à jour comme une réponse, plutôt que de modifier la question.


@Matt - Pas de mal fait. :) facilement roulé. Je suis d'accord avec Skizz si vous seriez formidable si vous pouviez poster votre code fixe comme réponse pour aider les futurs lecteurs à comprendre complètement le correctif.


@razlebe: fera, je dois attendre 5 heures, apparemment.


Fonction améliorée affichée, si quelqu'un est intéressé.



0
votes

a compris une solution; Voici ma fonction révisée qui fonctionne correctement.

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);

}


0 commentaires

1
votes

Parfois, les choses deviennent plus faciles si vous n'utilisez pas de pointeurs, mais des compensations. La bibliothèque STRSPN () et STRCSPN () fonctionne plus ou moins forcer à utiliser des compensations, et traiter avec la condition finale de chaîne assez joliment.

#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;
}                                                                                           


2 commentaires

Seriez-vous capable d'ajouter quelques commentaires à cela expliquant ce qui se passe? C'est un peu difficile à suivre, par exemple, ce qui se passe dans la fonction REVWOWWDWWOW.


Eh bien: Dans la boucle, je mesurise la longueur de l'espace blanche consécutive (l'appel STRSPN ()) et sautez-la. Après cela, je mesurais la longueur de WhitSpace sans WhitSpace (l'appel STRCSPN ()) et inversez-le. À la fin de la boucle, j'ai la longueur de la corde accumulée et inverser la chaîne entière.



0
votes

L'algorithme suivant est en place et fonctionne en 2 étapes. Tout d'abord, il inverse toute la chaîne. Ensuite, il renverse chaque mot.

#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;
}


1 commentaires

Si len est même, la fonction inverse provoquera un segfault. Essayez pendant (p .



0
votes
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
    }
}

0 commentaires