¿Cómo puedo reemplazar la primera aparición de un carácter en cada palabra?

44

¿Cómo puedo reemplazar la primera aparición de un carácter en cada palabra?

Digamos que tengo esta cadena:

hello @jon i am @@here or @@@there and want some@thing in '@here"
#     ^         ^^        ^^^                   ^          ^ 

Y quiero eliminar el primero @en cada palabra, para que termine teniendo una cadena final como esta:

hello jon i am @here or @@there and want something in 'here
#     ^        ^        ^^                   ^         ^

Solo para aclarar, los caracteres "@" siempre aparecen juntos en cada palabra, pero pueden estar al principio de la palabra o entre otros caracteres.

Logré eliminar el carácter "@" si aparece solo una vez usando una variación de la expresión regular que encontré en Eliminar subcadena cuando aparece una vez, pero no cuando dos veces seguidas en python , que usa una búsqueda anticipada negativa y una mirada negativa hacia atrás:

@(?!@)(?<!@@)

Ver la salida:

>>> s = "hello @jon i am @@here or @@@there and want some@thing in '@here"
>>> re.sub(r'@(?!@)(?<!@@)', '', s)
"hello jon i am @@here or @@@there and want something in 'here"

Entonces, el siguiente paso es reemplazar la "@" cuando ocurre más de una vez. Esto es fácil s.replace('@@', '@')al eliminar la "@" de donde sea que ocurra nuevamente.

Sin embargo, me pregunto: ¿hay alguna manera de hacer este reemplazo de una sola vez?

fedorqui 'así que deja de dañar'
fuente
1
¿Necesitas una respuesta estrictamente regex?
Sayandip Dutta
@SayandipDutta en principio, sí, pero también me gustaría ver otras formas de hacer lo mismo sin una expresión regular :)
fedorqui 'SO deja de dañar'
Solo para asegurarme, ¿podría haber una cadena como: ¿ @Hello@Theredónde @no sería consecutiva?
JvdV
1
@JvdV no, no habrá tal caso.
Fedorqui 'así que deja de dañar'

Respuestas:

51

Haría un reemplazo de expresiones regulares en el siguiente patrón:

@(@*)

Y luego simplemente reemplace con el primer grupo de captura, que es todo @ símbolos continuos, menos uno.

Esto debería capturar todo lo que @ocurre al comienzo de cada palabra, ya sea esa palabra al comienzo, en el medio o al final de la cadena.

inp = "hello @jon i am @@here or @@@there and want some@thing in '@here"
out = re.sub(r"@(@*)", '\\1', inp)
print(out)

Esto imprime:

hello jon i am @here or @@there and want something in 'here
Tim Biegeleisen
fuente
35

¿Qué hay de usar replace('@', '', 1)en una expresión generadora?

string = 'hello @jon i am @@here or @@@there and want some@thing in "@here"'
result = ' '.join(s.replace('@', '', 1) for s in string.split(' '))

# output: hello jon i am @here or @@there and want something in "here"

El valor int de 1es el countargumento opcional .

str.replace(old, new[, count])

Devuelve una copia de la cadena con todas las apariciones de la subcadena antigua reemplazada por nueva . Si se proporciona el recuento de argumentos opcional , solo se reemplazan las primeras ocurrencias de recuento .

Chico
fuente
55
Ese es un truco inteligente! Como el tercer parámetro de replace es replace(search, replace, max_matches), simplemente reemplaza el primero en cada palabra.
fedorqui 'así que deja de dañar'
1
@ fedorqui'SOstopharming 'sí, se llama count, agregué la descripción de los documentos.
Chico
2
Tenga cuidado con este efecto secundario: en caso de que tenga varios espacios en blanco (''), se perderán y se reemplazarán por uno solo ''.
Marc Vanhoomissen
4

Puedes usar re.subasí:

import re

s = "hello @jon i am @@here or @@@there and want some@thing in '@here"
s = re.sub('@(\w)', r'\1', s)
print(s)

Eso resultará en:

"hello jon i am @here or @@there and want something in 'here"

Y aquí hay una prueba de concepto:

>>> import re
>>> s = "hello @jon i am @@here or @@@there and want some@thing in '@here"
>>> re.sub('@(\w)', r'\1', s)
"hello jon i am @here or @@there and want something in 'here"
>>> 
accdias
fuente
2

Estaba reflexionando sobre los casos, y si solo el último carácter es @y no desea eliminarlo, o si tiene caracteres iniciales permitidos específicos, se le ocurrió esto:

>>> ' '.join([s_.replace('@', '', 1) if s_[0] in ["'", "@"] else s_ for s_ in s.split()])
"hello jon i am @here or @@there and want some@thing in 'here"

O bien, suponga que desea reemplazar @solo si está en los primeros n caracteres

>>> ' '.join([s_.replace('@', '', 1) if s_.find('@') in range(2) else s_ for s_ in s.split()])
"hello jon i am @here or @@there and want some@thing in 'here"
Sayandip Dutta
fuente
1
# Python3 program to remove the @ from String


def ExceptAtTheRate(string):
    # Split the String based on the space
    arrOfStr = string.split()

    # String to store the resultant String
    res = ""

    # Traverse the words and
    # remove the first @ From every word.
    for a in arrOfStr:
        if(a[0]=='@'):
            res += a[1:len(a)] + " "
        else:
            res += a[0:len(a)] + " "

    return res


# Driver code
string = "hello @jon i am @@here or @@@there and want some@thing in '@here"

print(ExceptAtTheRate(string))

Salida:

ingrese la descripción de la imagen aquí

Amar Kumar
fuente
¡Gracias! Tenga en cuenta que la @ dentro de algo @ y '@here también deberían eliminarse, según mis requisitos.
Fedorqui 'así que deja de dañar' el