2010-10-08 17 views
15

Dada la siguiente cadena, "Hi ~+ and ^*. Is ^* still flying around ~+?"C++ sustituir múltiples cadenas en una cadena de una sola pasada

quiero reemplazar todas las apariciones de "~+" y "^*" con "Bobby" y "Danny", por lo que la cadena se convierte en:

"Hi Bobby and Danny. Is Danny still flying around Bobby?"

Preferiría no tener que llamar a Boost replace function dos veces para reemplazar las ocurrencias de los dos valores diferentes.

+0

¿De dónde viene la cadena? – JoshD

+0

Como sabemos 'O (n) + O (n)' sigue siendo 'O (n)', ¿cuál es la motivación * real * aquí? – Arun

+1

La cadena/datos reales tiene un tamaño potencial de 100 gigabytes, se procesa de forma incremental y, si bien la sustitución de llamadas sigue siendo O (n), la n es bastante grande. –

Respuesta

0

Boost string_algo tiene una función replace_all. Podrías usar eso.

+0

Gracias Matthew, pero eso solo requiere un valor para convertir y necesitaría llamarlo dos veces. Estoy intentando descubrir que hay una manera de dar esencialmente un mapa, si encuentras que x1 reemplaza con y1 y x2 con y2, y así sucesivamente, y el escaneo sobre la cadena solo ocurre una vez. –

0

Sugiero usar la biblioteca Boost Format. En lugar de ~+ y ^*, utilice %1% y %2%, etc. un poco más sistemáticamente.

Ejemplo de los documentos:.

cout << boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50; 
    // prints "writing toto, x=40.230 : 50-th try" 

Saludos & HTH,

- Alf

+0

Gracias por la sugerencia Alf, sin embargo no tengo control sobre los datos de entrada por lo que su sugerencia no funcionará. Tengo que procesar el contenido y cambiar los valores dentro del especificado por el usuario que invoca el código. –

5

que logró llevar a cabo la función de sustitución deseado con Boost.Iostreams. Específicamente, el método que utilicé fue un flujo de filtrado que usa expresiones regulares para que coincida con lo que se debe reemplazar. No estoy seguro del rendimiento en archivos de tamaño de gigabyte. Necesitarás probarlo por supuesto. De todos modos, aquí está el código:

#include <boost/regex.hpp> 
#include <boost/iostreams/filter/regex.hpp> 
#include <boost/iostreams/filtering_stream.hpp> 
#include <iostream> 

int main() 
{ 
    using namespace boost::iostreams; 

    regex_filter filter1(boost::regex("~\\+"), "Bobby"); 
    regex_filter filter2(boost::regex("\\^\\*"), "Danny"); 

    filtering_ostream out; 
    out.push(filter1); 
    out.push(filter2); 
    out.push(std::cout); 

    out << "Hi ~+ and ^*. Is ^* still flying around ~+?" << std::endl; 

    // for file conversion, use this line instead: 
    //out << std::cin.rdbuf(); 
} 

Las impresiones anteriores "Hi Bobby and Danny. Is Danny still flying around Bobby?" cuando se ejecuta, al igual que lo esperado.

Sería interesante ver los resultados de rendimiento, si decides medirlo.

Daniel

Edit: acabo de dar cuenta que regex_filter tiene que leer toda la secuencia de caracteres en la memoria, por lo que es bastante inútil para las entradas de gigabytes de tamaño. Oh, bueno ...

0

Sugeriría usar std :: map. Por lo que tiene un conjunto de sustituciones, por lo que hace:

std::map<std::string,std::string> replace; 
replace["~+"]=Bobby; 
replace["^*"]=Danny; 

entonces se podría poner la cadena en un vector de cadenas y comprobar para ver si cada cadena tiene lugar en el mapa y si no reemplazarlo, que había también necesita quitar cualquier signo de puntuación del final. O agréguelos a los reemplazos. Podrías hacerlo en un ciclo. No estoy seguro de si esto es realmente más eficiente o útil que impulsar.

3

Me di cuenta de que ha pasado un año desde que esto estuvo activo, pero por lo que vale la pena. I came across an article on CodeProject hoy que pretende resolver este problema - tal vez pueda usar ideas de allí:

No puedo responder por su corrección, pero podría valer la pena echarle un vistazo.:)

La implementación seguramente requiere mantener toda la cadena en la memoria, pero puede solucionarla fácilmente (como con cualquier otra implementación que realice las sustituciones) siempre que pueda dividir la entrada en bloques y garantizar que nunca dividir en una posición que es dentro de un símbolo que debe reemplazarse. (Una manera fácil de hacer que en su caso es dividir en una posición en la próxima carbón no es ninguno de los caracteres utilizados en un símbolo.)

-

hay una razón más allá del rendimiento (aunque es una razón suficiente en mi libro) para agregar un método "ReemplazarMúltiples" a la biblioteca de cadenas de uno: Simplemente hacer la operación de reemplazo N veces NO es correcto en general.

Si los valores que están sustituidos para los símbolos no están limitados, valores pueden llegar a ser tratados como símbolos en operaciones posteriores de reemplazar. (Podría haber situaciones en las que realmente desea esto, pero definitivamente hay casos en que no lo hace. Usar símbolos de aspecto extraño reduce la gravedad del problema, pero no lo resuelve, y "es feo" porque las cadenas a formatear pueden ser definibles por el usuario, por lo que no deberían requerir caracteres exóticos.)

Sin embargo, sospecho que hay una buena razón por la cual no puedo encontrar fácilmente una implementación general de múltiples reemplazos. Una operación "ReemplazarMúltiples" simplemente no está (obviamente) bien definida en general.

Para ver esto, considere lo que podría significar para "reemplazar" aa 'con'! ' y 'baa' con '?' en la cadena 'abaa' "? Es el resultado 'ab!' o 'a?' - o es un reemplazo ilegal?

Uno podría requerir que los símbolos estén "sin prefijo", pero en muchos casos eso sería inaceptable. Supongamos que quiero usar esto para formatear texto de plantilla. Y decir que mi plantilla es para el código. Quiero reemplazar "§table" con un nombre de tabla de base de datos conocido solo en tiempo de ejecución. Sería molesto si ahora no pudiera usar "§t" en la misma plantilla. El script con plantilla podría ser algo completamente genérico, y he aquí, un día me encuentro con el cliente que realmente hizo uso de "§" en los nombres de su tabla ... lo que hace que mi biblioteca de plantillas sea menos útil.

Una solución quizás mejor sería usar un analizador de descenso recursivo en lugar de simplemente reemplazar literales. :)

Cuestiones relacionadas