2015-05-30 14 views
8

Così, per l'ingresso:Sostituire nella stringa sulla base della funzione ouput

accessibility,random good bye 

Voglio uscita:

a11y,r4m g2d bye 

Quindi, in sostanza, devo abbreviare tutte le parole di lunghezza maggiore o uguale a 4 nel seguente formato: first_letter + length_of_all_letters_in_between + last_letter

cerco di fare questo:

re.sub(r"([A-Za-z])([A-Za-z]{2,})([A-Za-z])", r"\1" + str(len(r"\2")) + r"\3", s) 

Ma non funziona. In JS, avrei facilmente fare:

str.replace(/([A-Za-z])([A-Za-z]{2,})([A-Za-z])/g, function(m, $1, $2, $3){ 
    return $1 + $2.length + $3; 
}); 

Come faccio a fare lo stesso in Python?

MODIFICA: Non posso permettermi di perdere alcuna punteggiatura presente nella stringa originale.

+2

're' è un po 'eccessivo per questo, a mio parere. Userei semplicemente 'mystring [0] + str (len (mystring) -2) + mystring [-1]' e un'istruzione 'if' per vedere quando applicare questo –

+0

@AleksanderLidtke Ci ho pensato ma poi' mystring 'ha singole parole separate (come' accessibilità, random good arrivederci ') e non è una parola. –

+0

@AleksanderLidtke, che dire della virgola? Come stai separando le parole? –

risposta

3

Il problema che si sta verificando è che len(r'\2') è sempre 2, non la lunghezza del secondo gruppo di acquisizione nell'espressione regolare. È possibile utilizzare un'espressione lambda per creare una funzione che funziona proprio come il codice che si usa in JavaScript:

re.sub(r"([A-Za-z])([A-Za-z]{2,})([A-Za-z])", 
     lambda m: m.group(1) + str(len(m.group(2)) + m.group(3), 
     s) 

La m argomento per il lambda è un oggetto match, e le chiamate al suo metodo group sono equivalenti a le backreferences che stavi usando in precedenza.

Potrebbe essere più facile utilizzare solo un semplice schema parola corrispondente senza gruppi di cattura (group() può ancora essere chiamato senza alcun argomento per ottenere l'intero testo corrispondente):

re.sub(r'\w{4,}', lambda m: m.group()[0] + str(len(m.group())-2) + m.group()[-1], s) 
+0

nag molto breve che l'autore ha usato '[A-Za-z]' nella sua soluzione originale e che potresti voler cambiare la tua soluzione alternativa a quella invece di '\ w'. – Cu3PO42

+0

Accettato per dare una soluzione e per evidenziare il mio problema. –

2
tmp, out = "","" 
for ch in s: 
    if ch.isspace() or ch in {",", "."}: 
     out += "{}{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1], ch) if len(tmp) > 3 else tmp + ch 
     tmp = "" 
    else: 
     tmp += ch 
out += "{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1]) if len(tmp) > 3 else tmp 
print(out) 

a11y,r4m g2d bye 

Se desideri solo caratteri alfa utilizzano str.isalpha:

tmp, out = "", "" 
for ch in s: 
    if not ch.isalpha(): 
     out += "{}{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1], ch) if len(tmp) > 3 else tmp + ch 
     tmp = "" 
    else: 
     tmp += ch 
out += "{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1]) if len(tmp) > 3 else tmp 
print(out) 
a11y,r4m g2d bye 

La logica è la stessa per entrambi, è proprio quello che controlliamo per che si differenzia, se not ch.isalpha() è falso abbiamo trovato un carattere non alpha, quindi dobbiamo elaborare la stringa tmp e aggiungerla alla stringa di output. if len(tmp) non è maggiore di 3 in base al requisito, aggiungiamo semplicemente la stringa tmp più il carattere corrente alla nostra stringa esterna.

Abbiamo bisogno di un finale out += "{}{}{} fuori dal ciclo per catturare quando una stringa non finisce in una virgola, spazio ecc. Se la stringa terminasse in un non-alfa, aggiungeremmo una stringa vuota in modo da non rendere differenza per l'uscita.

Si manterrà la punteggiatura e spazi:

s = "accessibility,random good bye !! foobar?" 
def func(s): 
    tmp, out = "", "" 
    for ch in s: 
     if not ch.isalpha(): 
      out += "{}{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1], ch) if len(tmp) > 3 else tmp + ch 
      tmp = "" 
     else: 
      tmp += ch 
    return "{}{}{}".format(tmp[0], len(tmp) - 2, tmp[-1]) if len(tmp) > 3 else tmp 
print(func(s,3)) 
a11y,r4m g2d bye !! f4r? 
+0

Puoi spiegare la logica di questo codice? –

7

Quello che state facendo in JavaScript è sicuramente giusto, si sta passando una funzione anonima. Quello che fai in Python è di passare un'espressione costante ("\ 12 \ 3", poiché len(r"\2") viene valutata prima della chiamata alla funzione), non è una funzione che può essere valutata per ogni corrispondenza!

Mentre funzioni anonime in Python non sono così utili come sono in JS, che fanno il lavoro qui:

>>> import re 
>>> re.sub(r"([A-Za-z])([A-Za-z]{2,})([A-Za-z])", lambda m: "{}{}{}".format(m.group(1), len(m.group(2)), m.group(3)), "accessability, random good bye") 
'a11y, r4m g2d bye' 

Cosa succede qui è che il lambda viene chiamata per ogni sostituzione, prendendo un match oggetto. Quindi recupero le informazioni necessarie e costruisco una stringa di sostituzione da quella.

+4

@Kasra come è?Fa esattamente ciò che l'autore voleva ed è una stretta analogia con il suo codice in JS – Cu3PO42

+0

@Kasra infatti lo fa. Questo è completamente indipendente dalla punteggiatura. – Cu3PO42

0

Utilizzando regex e comprensione:

import re 
s = "accessibility,random good bye" 
print "".join(w[0]+str(len(w)-2)+w[-1] if len(w) > 3 else w for w in re.split("(\W)", s)) 

Dà:

a11y,r4m g2d bye 
+0

Questo abbrevia ogni carattere a quattro o più caratteri a lungo termine di caratteri non di parole. Prova 's = 'foo ... bar'' per vedere di persona! – Blckknght

+0

@Blckknght, grazie, corretto – perreal

-1

Date un'occhiata al seguente codice di

sentence = "accessibility,random good bye" 
sentence = sentence.replace(',', " ") 
sentence_list = sentence.split(" ") 
for item in sentence_list: 
    if len(item) >= 4: 
     print item[0]+str(len(item[1:len(item)-1]))+item[len(item)-1] 

L'unica cosa che si dovrebbe prendere cura di una virgola e altri caratteri di punteggiatura.

1

Come un modo preciso alternativo voi è possibile utilizzare una funzione separata per re.sub e utilizzare la semplice espressione regolare r"(\b[a-zA-Z]+\b)".

>>> def replacer(x): 
... g=x.group(0) 
... if len(g)>3: 
...  return '{}{}{}'.format(g[0],len(g)-2,g[-1]) 
... else : 
...  return g 
... 
>>> re.sub(r"(\b[a-zA-Z]+\b)", replacer, s) 
'a11y,r4m g2d bye' 

anche come divinatorio e generale modo, per ottenere le parole sostituite all'interno di un elenco è possibile utilizzare un elenco di comprensione utilizzando re.finditer:

>>> from operator import sub 
>>> rep=['{}{}{}'.format(i.group(0)[0],abs(sub(*i.span()))-2,i.group(0)[-1]) if len(i.group(0))>3 else i.group(0) for i in re.finditer(r'(\w+)',s)] 
>>> rep 
['a11y', 'r4m', 'g2d', 'bye'] 

Il re.finditer volontà restituisce un generatore contiene tutte matchobjects quindi è possibile scorrere su di esso e ottenere l'inizio e la fine di matchobject s con il metodo span().

1

Keep it simple ...

>>> s = "accessibility,random good bye" 
>>> re.sub(r'\B[A-Za-z]{2,}\B', lambda x: str(len(x.group())), s) 
'a11y,r4m g2d bye' 

\B che corrisponde tra due caratteri parola o due caratteri non-parola aiuta a soddisfare tutti i caratteri ad eccezione di primo e l'ultimo.

+0

Eccellente! Non ci ho mai pensato! –

Problemi correlati