string - script - Modificar un personaje en una cadena en Lua
string byte (2)
¿Hay alguna manera de reemplazar un personaje en la posición N en una cadena en Lua?
Esto es lo que he propuesto hasta ahora:
function replace_char(pos, str, r)
return str:sub(pos, pos - 1) .. r .. str:sub(pos + 1, str:len())
end
str = replace_char(2, "aaaaaa", "X")
print(str)
No puedo usar gsub ya que eso reemplazaría todas las capturas, no solo la captura en la posición N.
Debe usar pos
dentro de su función en lugar de literal 1
y 3
, pero aparte de esto, se ve bien. Como las cuerdas de Lua son inmutables, no se puede hacer mucho mejor que esto.
Tal vez
"%s%s%s":format(str:sub(1,pos-1), r, str:sub(pos+1, str:len())
es más eficiente que el ..
operador, pero lo dudo, si se trata de un cuello de botella, mídelo (y luego decida implementar esta función de reemplazo en C).
Las cuerdas en Lua son inmutables. Eso significa que cualquier solución que reemplace texto en una cadena debe terminar construyendo una nueva cadena con el contenido deseado. Para el caso específico de reemplazar un solo personaje con otro contenido, deberá dividir la cadena original en una parte de prefijo y una parte de postfijo, y volver a concatenarlos alrededor del nuevo contenido.
Esta variación en tu código:
function replace_char(pos, str, r)
return str:sub(1, pos-1) .. r .. str:sub(pos+1)
end
es la traducción más directa a Lua directo. Probablemente sea lo suficientemente rápido para la mayoría de los propósitos. He solucionado el error de que el prefijo debería ser el primer carácter pos-1
, y aproveché el hecho de que si falta el último argumento para string.sub
, se supone que es -1
que es equivalente al final del cuerda.
Pero tenga en cuenta que crea una serie de cadenas temporales que se mantendrán en la tienda de cadenas hasta que la recolección de basura se las coma. Los temporales para el prefijo y el sufijo no se pueden evitar en ninguna solución. Pero esto también tiene que crear un temporal para que el primer operador sea consumido por el segundo.
Es posible que uno de los dos enfoques alternativos sea más rápido. La primera es la solución ofrecida por PaĆlo Ebermann , pero con una pequeña modificación:
function replace_char2(pos, str, r)
return ("%s%s%s"):format(str:sub(1,pos-1), r, str:sub(pos+1))
end
Esto usa string.format
para hacer el ensamblaje del resultado con la esperanza de que adivine el tamaño final del búfer sin necesidad de objetos temporales adicionales.
Pero tenga cuidado de que string.format
tenga problemas con cualquier carácter /0
en cualquier cadena que pase por su formato %s
. Específicamente, dado que se implementa en términos de la función sprintf()
estándar de C, sería razonable esperar que termine la cadena sustituida en la primera aparición de /0
. (Observado por el usuario Delusional Logic en un comentario).
Una tercera alternativa que viene a la mente es esta:
function replace_char3(pos, str, r)
return table.concat{str:sub(1,pos-1), r, str:sub(pos+1)}
end
table.concat
concatena eficientemente una lista de cadenas en un resultado final. Tiene un segundo argumento opcional que es texto para insertar entre las cadenas, cuyo valor predeterminado es ""
que se ajusta a nuestro propósito aquí.
Supongo que a menos que tus cadenas sean enormes y hagas esta sustitución con frecuencia, no verás ninguna diferencia de rendimiento práctica entre estos métodos. Sin embargo, me ha sorprendido antes, así que perfile su aplicación para verificar que haya un cuello de botella y compare las posibles soluciones cuidadosamente.