Pregunta

Me encontré con un código y me preguntaba qué estaba haciendo el desarrollador original.A continuación se muestra un programa simplificado que utiliza este patrón:

      #include <stdio.h>

      int main()  {     

      char title[80] = "mytitle";      
      char title2[80] = "mayataiatale";      
      char mystring[80]; 

      /* hugh ? */
      sscanf(title,"%[^a]",mystring);
      printf("%s\n",mystring); /* Output is "mytitle" */


      /* hugh ? */
      sscanf(title2,"%[^a]",mystring); /* Output is "m" */
      printf("%s\n",mystring);


      return 0;  
  }

El página de manual para scanf tiene información relevante, pero tengo problemas para leerla.¿Cuál es el propósito de utilizar este tipo de notación?¿Qué está tratando de lograr?

¿Fue útil?

Solución

La razón principal de las clases de personajes es para que la notación% s se detiene en el primer carácter de espacio en blanco, incluso si se especifica longitudes de campo, y que muy a menudo no quieren que lo haga. En ese caso, la notación clase de caracteres puede ser extremadamente útil.

Considere este código para leer una línea de hasta 10 caracteres, descartando cualquier exceso, pero manteniendo espacios:

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

int main(void)
{
    char buffer[10+1] = "";
    int rc;
    while ((rc = scanf("%10[^\n]%*[^\n]", buffer)) >= 0)
    {
            int c = getchar();
            printf("rc = %d\n", rc);
            if (rc >= 0)
                    printf("buffer = <<%s>>\n", buffer);
            buffer[0] = '\0';
    }
    printf("rc = %d\n", rc);
    return(0);
}

Este fue en realidad código de ejemplo para una discusión sobre comp.lang.c.moderated (alrededor de junio de 2004) en relación con getline() variantes.


Al menos algunos reina la confusión. El primer especificador de formato, %10[^\n], lee hasta 10 caracteres que no sean de nueva línea y que están asignados a amortiguar, junto con un nulo final. El segundo formato especificador, %*[^\n] contiene el carácter de supresión de asignación (*) y lee cero o más restantes caracteres no de nueva línea de la entrada. Cuando la función scanf() completa, la entrada está apuntando a la siguiente carácter de nueva línea. El cuerpo del bucle lee e imprime ese carácter, por lo que cuando se reinicia el bucle, la entrada está mirando al inicio de la siguiente línea. El proceso se repite entonces. Si la línea es más corto de 10 caracteres, entonces esos caracteres se copian para amortiguar y formato de los 'cero o más que no son nuevas líneas' procesos distintos de cero nuevas líneas.

Otros consejos

Las construcciones como %[a] y %[^a] existir para que scanf() Puede utilizarse como una especie de analizador léxico.Estos son algo así como %s, pero en lugar de recopilar una serie de tantos caracteres "fibrosos" como sea posible, recopilan solo una serie de caracteres como los describe la clase de personaje.Puede haber casos en los que escribir %[a-zA-Z0-9] podría tener sentido, pero no estoy seguro de ver un caso de uso convincente para clases complementarias con scanf().

EN MI HUMILDE OPINIÓN, scanf() simplemente no es la herramienta adecuada para este trabajo.Cada vez que me propuse utilizar una de sus funciones más potentes, terminé eliminándola e implementando la capacidad de una manera diferente.En algunos casos, eso significó usar lex para escribir un analizador léxico real, pero generalmente haciendo E/S de línea en línea y dividiéndola en tokens con strtok() antes de hacer la conversión de valor era suficiente.

Editar: Terminé arrancando scanf() Por lo general, porque cuando se enfrentan a los usuarios que insisten en proporcionar una entrada incorrecta, simplemente no es bueno ayudar al programa a dar buenos comentarios sobre el problema, y ​​tener una impresión de ensamblador "error, terminado". Como su único mensaje de error útil no estaba bien con mi usuario.(Yo, en ese caso.)

Es como los juegos de caracteres de expresiones regulares; [0-9] coincide con una cadena de dígitos, [^aeiou] coincide con nada que no sea una vocal minúscula, etc.

Hay todo tipo de usos, como sacando los números, identificadores, trozos de espacios en blanco, etc.

Puede leer sobre él en el ISO / IEC9899 estándar disponible en línea.

Este es un párrafo cito del documento sobre [ (Página 286):

  

Encaja en una secuencia no vacía de caracteres de un conjunto de espera   personajes.

     

El especificador de conversión incluye todos los caracteres posteriores en el   cadena de formato, hasta e incluyendo el soporte derecho de surtidos (]). los   caracteres entre los corchetes (la lista de exploración) componen el scanset,   a menos que el carácter después del paréntesis de la izquierda es un acento circunflejo (^), en   cuyo caso el scanset contiene todos los caracteres que no aparecen en   la lista de exploración entre la circunfleja y el soporte derecho. Si el   especificador de conversión comienza con [] o [^], el soporte derecho   personaje está en la lista de exploración y la siguiente siguiente soporte derecho   carácter es el soporte derecho a juego que termina la especificación;   de lo contrario el primer carácter siguiente soporte derecho es el que   termina la especificación. Si un - personaje está en la lista de exploración y no es   el primero, ni el segundo, donde el primer carácter es un ^, ni el   último carácter, el comportamiento es definido por la implementación.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top