Como posso substituir a primeira ocorrência de um caractere em cada palavra?

44

Como posso substituir a primeira ocorrência de um caractere em cada palavra?

Digamos que eu tenho esta string:

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

E eu quero remover a primeira @em cada palavra, para que eu tenha uma sequência final como esta:

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

Apenas para esclarecimento, os caracteres "@" sempre aparecem juntos em todas as palavras, mas podem estar no início da palavra ou entre outros caracteres.

Eu consegui remover o caractere "@" se ele ocorrer apenas uma vez, usando uma variação do regex que encontrei em Excluir substring quando ocorre uma vez, mas não quando duas vezes seguidas em python , que usa um lookahead negativo e um lookback negativo:

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

Veja a saída:

>>> 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"

Portanto, o próximo passo é substituir o "@" quando ocorrer mais de uma vez. Isso é fácil, s.replace('@@', '@')removendo o "@" de onde ele ocorre novamente.

No entanto, eu me pergunto: existe uma maneira de fazer essa substituição de uma só vez?

fedorqui 'Então pare de prejudicar'
fonte
11
Você precisa de uma resposta estritamente regular?
Sayandip Dutta 25/02
@SayandipDutta em princípio, sim, mas eu também ficaria curioso para ver outras maneiras de fazer o mesmo sem uma regex :)
fedorqui 'SO stop stop male'
Só para ter certeza, poderia haver uma string como: @Hello@Thereonde @não seria consecutivo?
JvdV 25/02
11
@JvdV não, não haverá esse caso.
fedorqui 'SO stop prejudicar'

Respostas:

51

Eu faria uma substituição de regex no seguinte padrão:

@(@*)

E então substitua pelo primeiro grupo de captura, que é todo contínuo @ símbolos, menos um.

Isso deve capturar todas as @ocorrências no início de cada palavra, seja essa no início, no meio ou no final da sequência.

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

Isso imprime:

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

Que tal usar replace('@', '', 1)em uma expressão geradora?

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"

O valor int de 1é o countargumento opcional .

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

Retorne uma cópia da sequência com todas as ocorrências de substring antigas substituídas por novas . Se a contagem opcional de argumentos for fornecida, apenas as primeiras ocorrências de contagem serão substituídas.

Cara
fonte
5
Esse é um truque inteligente! Como o terceiro parâmetro de replace é replace(search, replace, max_matches), ele substitui o primeiro de cada palavra.
fedorqui 'SO stop prejudicar'
11
@ fedorqui'SOstopharming 'sim, é chamado count, eu adicionei a descrição dos documentos.
Guy
2
Cuidado com este efeito colateral: caso você tenha vários espaços em branco (''), eles serão perdidos e substituídos por um único ''.
Marc Vanhoomissen 28/02
4

Você pode usar re.subassim:

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)

Isso resultará em:

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

E aqui está uma prova de conceito:

>>> 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
fonte
2

Estava pensando em casos e se apenas o último caractere é @e você não deseja removê-lo, ou se você tem caracteres iniciais permitidos específicos, veio com isso:

>>> ' '.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"

Ou, suponha que você queira substituir @apenas se estiver nos primeiros 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
fonte
2

DEMO

(?<!@)@

Você pode tentar isso. Veja a demonstração.

vks
fonte
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))

Resultado:

insira a descrição da imagem aqui

Amar Kumar
fonte
Obrigado! Observe que o @ dentro de alguma coisa @ e '@here também devem ser removidos, conforme meus requisitos.
fedorqui 'SO stop harming'