2013-02-14 16 views
6

Ho una regex verbose python stringa (con un sacco di spazi e commenti) che mi piacerebbe convertire in stile "normale" (per l'esportazione in javascript). In particolare, ho bisogno che questo sia abbastanza affidabile. Se c'è un modo dimostrabilmente corretto per farlo, è quello che voglio. Ad esempio, un'implementazione ingenua distruggerebbe un'espressione regolare come r' \# # A literal hash character', che non è OK.strip a verbose python regex

Il modo migliore per farlo sarebbe quello di forzare il modulo python re per restituirmi una rappresentazione non verbosa della mia regex, ma non vedo un modo per farlo.

+2

quanto pare qualcuno ha fatto questo, ma è in JavaScript http://blog.mackerron.com/2010/08/08/extended-multi-line-js-regexps/ –

+0

Sfortunatamente, converte una sintassi regex personalizzata verbose nella sintassi regex di JS, che non è esattamente la stessa cosa che converte la sintassi regex di Python sintassi con la sintassi regex non verbosa di Python ... ma potresti sicuramente usare quel codice come modello per scrivere il tuo equivalente Python, se non riesci a trovarne uno – abarnert

+0

Questo non dovrebbe essere troppo difficile. Basta rimuovere prima di un \ n ma prima di un # e rimuovere tutto ciò che corrisponde a \ w ma non a \ \ w. – Linuxios

risposta

4

Credo che avete solo bisogno di affrontare questi due problemi per mettere a nudo una regex verbose:

  1. eliminare i commenti alla fine della linea di
  2. eliminare gli spazi senza caratteri di escape

provare questo, che le catene il 2 con sostituzioni regex separati:

import re 

def unverbosify_regex_simple(verbose): 
    WS_RX = r'(?<!\\)((\\{2})*)\s+' 
    CM_RX = r'(?<!\\)((\\{2})*)#.*$(?m)' 

    return re.sub(WS_RX, "\\1", re.sub(CM_RX, "\\1", verbose)) 

Quanto sopra è una semplificazione d versione che lascia gli spazi con escape così com'è. L'output risultante sarà un po 'più difficile da leggere ma dovrebbe funzionare per le piattaforme regex.

In alternativa, per una risposta un po 'più complesso che spazi "converte in caratteri escape" (cioè, '\'=>' ') e restituisce quello che penso la maggior parte delle persone che ci si aspetta:

import re 

def unverbosify_regex(verbose): 
    CM1_RX = r'(?<!\\)((\\{2})*)#.*$(?m)' 
    CM2_RX = r'(\\)?((\\{2})*)(#)' 
    WS_RX = r'(\\)?((\\{2})*)(\s)\s*' 

    def strip_escapes(match): 
     ## if even slashes: delete space and retain slashes 
     if (match.group(1) is None): 
     return match.group(2) 

     ## if number of slashes is odd: delete slash and keep space (or 'comment') 
     elif (match.group(1) == '\\'): 
     return match.group(2) + match.group(4) 

     ## error 
     else: 
     raise Exception 

    not_verbose_regex = re.sub(WS_RX, strip_escapes, 
         re.sub(CM2_RX, strip_escapes, 
         re.sub(CM1_RX, "\\1", 
          verbose))) 

    return not_verbose_regex 

UPDATE: aggiunto commenti per spiegare anche v. conteggio delle barrette dispari. È stato corretto il primo gruppo in CM_RX per mantenere il "commento" completo se il conteggio delle barre è dispari.

UPDATE 2: I commenti regolari regex, che non si occupavano correttamente degli hash escape. Dovrebbe gestire sia "\ # #escaped hash", così come "# commento con \ # sfuggito hash" e "\\ # comment"

UPDATE 3: Aggiunta una versione semplificata che non ripulire spazi sfuggiti .

AGGIORNAMENTO 4: ulteriore semplificazione per eliminare lunghezza variabile lookbehind negativo (e invertire/trucco inverso)

+0

Per migliorare la tua risposta, puoi anche convertire ''\'' a ''',' '\ # '' a '' # ''. – Ray

+0

Il punto 2 deve essere modificato per indicare "eccetto quando si verificano in insiemi", il che rende l'implementazione molto più complessa. – user4815162342

+0

Grazie - risposta aggiornata per annullare la scansione degli spazi e degli hash. – dpkp