2008-09-22 11 views
8

Ok, antes de siquiera hacer mi pregunta, quiero dejar una cosa clara. Actualmente soy estudiante de NIU en Informática y esto se relaciona con una de mis tareas para una clase allí. Entonces, si alguien tiene un problema, no siga leyendo y continúe con su negocio.Limpiar una cadena de puntuación en C++

Ahora para cualquier persona que esté dispuesta a ayudar, aquí está la situación. Para mi tarea actual, tenemos que leer un archivo que es solo un bloque de texto. Para cada palabra en el archivo, debemos borrar cualquier puntuación en la palabra (por ejemplo, "can not" podría terminar como "can" y "that - to" terminaría como "that" obviamente sin las comillas, las citas se usaron solo para especificar el ejemplo).

El problema que me he encontrado es que puedo limpiar bien la cadena y luego insertarla en el mapa que estamos usando, pero por alguna razón el código que he escrito permite insertar una cadena vacía en el mapa. Ahora he intentado todo lo que puedo pensar para evitar que esto suceda y lo único que se me ocurre es utilizar el método de borrado dentro de la propia estructura del mapa.

Así que lo que estoy buscando son dos cosas, cualquier sugerencia sobre cómo podría a) arreglar esto sin simplemente borrarlo yb) cualquier mejora que pueda hacer en el código que ya he escrito.

Aquí están las funciones que he escrito para leer desde el archivo y luego la que lo limpia.

Nota: la función que lee desde el archivo llama a la función clean_entry para eliminar la puntuación antes de insertar algo en el mapa.

Editar: Gracias Chris. Los números están permitidos :). Si alguien tiene alguna mejora en el código que he escrito o cualquier crítica de algo que hice, lo escucharé. En la escuela, realmente no recibimos retroalimentación sobre la forma correcta, adecuada o más eficiente de hacer las cosas.

int get_words(map<string, int>& mapz) 
{ 
int cnt = 0;    //set out counter to zero 

map<string, int>::const_iterator mapzIter; 

ifstream input;   //declare instream 
input.open("prog2.d"); //open instream 
assert(input);   //assure it is open 

string s;     //temp strings to read into 
string not_s; 

input >> s; 

while(!input.eof())  //read in until EOF 
    { 
    not_s = ""; 
    clean_entry(s, not_s); 

    if((int)not_s.length() == 0) 
    { 
    input >> s; 
    clean_entry(s, not_s); 
    }  

    mapz[not_s]++;    //increment occurence 
    input >>s; 
    } 
input.close();  //close instream 

for(mapzIter = mapz.begin(); mapzIter != mapz.end(); mapzIter++) 
    cnt = cnt + mapzIter->second; 

return cnt;  //return number of words in instream 
} 


void clean_entry(const string& non_clean, string& clean) 
{ 
int i, j, begin, end; 

for(i = 0; isalnum(non_clean[i]) == 0 && non_clean[i] != '\0'; i++); 

begin = i; 

if(begin ==(int)non_clean.length()) 
    return; 

for(j = begin; isalnum(non_clean[j]) != 0 && non_clean[j] != '\0'; j++); 

end = j; 

clean = non_clean.substr(begin, (end-begin)); 

for(i = 0; i < (int)clean.size(); i++) 
    clean[i] = tolower(clean[i]); 

} 
+0

Regístrese para la divulgación completa –

+0

Lo mismo aquí. También aprecio que Brandon obviamente puso mucho esfuerzo en su trabajo antes de hacer la pregunta. –

+0

No tengo ningún problema con que alguien pida ayuda para una tarea cuando primero han intentado completarla. Son las personas perezosas las que nos piden que hagamos todo su trabajo por ellos que me molesta. –

Respuesta

7

El problema con las entradas vacías está en su ciclo while. Si obtiene una cadena vacía, limpia la siguiente y la agrega sin verificar. Prueba a cambiar:

not_s = ""; 
clean_entry(s, not_s); 

if((int)not_s.length() == 0) 
{ 
    input >> s; 
    clean_entry(s, not_s); 
}  

mapz[not_s]++;    //increment occurence 
input >>s; 

a

not_s = ""; 
clean_entry(s, not_s); 

if((int)not_s.length() > 0) 
{ 
    mapz[not_s]++;    //increment occurence 
}  

input >>s; 

EDIT: Me he dado cuenta que está comprobando si los caracteres alfanuméricos. Si los números no están permitidos, es posible que deba volver a visitar esa área también.

+0

Bastante bien. Otra opción sería un bucle do-while: ingresar, limpiar y bucle mientras length == 0 –

+0

AviewAnew, asumiendo que lo entiendo correctamente, eso no funcionaría si se encuentra una palabra que comience con un signo de puntuación en el cuerpo del texto. –

+0

En realidad, se rompería en un trabajo que consiste completamente en caracteres no alfa. –

1

Una cadena en blanco es una instancia válida de la clase de cadena, por lo que no tiene nada de especial agregarla al mapa. Lo que podría hacer es primer cheque si está vacío, y sólo incremento en ese caso:

if (!not_s.empty()) 
    mapz[not_s]++; 
Por el estilo, hay algunas cosas que cambiaría, uno sería volver limpia de clean_entry en lugar de modificarlo

:

string not_s = clean_entry(s); 
... 
string clean_entry(const string &non_clean) 
{ 
    string clean; 
    ... // as before 
    if(begin ==(int)non_clean.length()) 
     return clean; 
    ... // as before 
    return clean; 
} 

Esto hace que sea más claro cuál es la función que está haciendo (teniendo una cadena, y devolver algo basado en esa cadena).

+0

Me gusta su idea y si tuviera el control total sobre la escritura del programa, lo más probable es que lo haga como usted dice, pero en cambio me limito al esquema que nos dan donde han definido los encabezados para la función que vamos a implementar.Gracias sin embargo. –

2

Otras mejoras serían

  • declarar variables sólo cuando se los utiliza, y en el ámbito más interno
  • uso C++ - estilo arroja en lugar del estilo C (int) arroja
  • uso vacíos() en lugar de longitud ==() 0 comparaciones
  • utilizan el operador de incremento prefijo para los iteradores (es decir ++mapzIter)
+0

¿Cuál es el beneficio de mover el ++ al principio? –

+0

mapzIter ++ primero devuelve una copia del iterador y luego incrementa el iterador. ++ mapzIter simplemente incrementa el iterador. – Eclipse

+0

Esa es otra pregunta que se responde aquí: http://stackoverflow.com/questions/24901/is-there-a-performance-difference-between-i-and-i-in-c –

1

La función 'getWords' está haciendo una gran cantidad de acciones distintas que podrían dividirse en otras funciones. Hay una buena posibilidad de que al dividirlo en partes individuales, usted mismo haya encontrado el error.

A partir de la estructura básica, creo que se podría dividir el código en (al menos):

  • getNextWord: Devuelve la siguiente palabra (no blanco) de la corriente (devuelve false si ninguno izquierda)
  • clean_entry: Lo que tiene ahora
  • getNextCleanWord: Llamadas getNextWord, y si 'verdadero' llama a CleanWord. Devuelve 'falso' si no quedan palabras.

Las firmas de 'getNextWord' y 'getNextCleanWord' podría ser algo como:

bool getNextWord (std::ifstream & input, std::string & str); 
bool getNextCleanWord (std::ifstream & input, std::string & str); 

La idea es que cada función tiene una parte más pequeña distinta del problema. Por ejemplo, 'getNextWord' no hace más que obtener la siguiente palabra no en blanco (si hay una). Por lo tanto, esta pieza más pequeña se convierte en una parte más fácil del problema para resolver y depurar si es necesario.

El componente principal de '' getWords luego pueden ser simplificados a:

std::string nextCleanWord; 
while (getNextCleanWord (input, nextCleanWord)) 
{ 
    ++map[nextCleanWord]; 
} 

Un aspecto importante para el desarrollo, en mi humilde opinión, es tratar de dividir y conquistar el problema. Dividirlo en las tareas individuales que deben llevarse a cabo. Estas subtareas serán más fáciles de completar y también deberían ser más fáciles de mantener.

Cuestiones relacionadas