2010-01-26 12 views
6

Abbiamo un ArrayList di elementi in diverse classi che mi danno problemi ogni volta che vorrei inserire un nuovo elemento nell'elenco. È stato un errore da parte mia aver disegnato le classi nel modo in cui l'ho fatto, ma cambiare il design ora sarebbe più mal di testa di quello che vale (modello burocratico a cascata). Avrei dovuto prevedere cambiamenti di formato ai documenti che il cliente ci stava fornendo cascata sii dannatoCodice di riformattazione con espressioni regolari

Mi piacerebbe scrivere un semplice script in python che entri in una classe, aggiunge l'elemento all'elenco e quindi incrementa tutti i retrieval per i seguenti elementi. Non mi sembra molto esplicativo:

Foo extends Bar{ 
    public Foo(){ 
     m_Tags.add("Jane"); 
     m_Tags.add("Bob"); 
     m_Tags.add("Jim"); 
    } 

    public String GetJane() { return m_ParsedValue.get(m_Tags.get(1)); } 
    public String GetBob() { return m_ParsedValue.get(m_Tags.get(2)); } 
    public String GetJim() { return m_ParsedValue.get(m_Tags.get(3)); } 
} 

Vedete se voglio aggiungere un valore tra "Jane" e "Bob" Ho poi dovuto incrementare i numeri interi nelle Funzioni Get *. Voglio solo scrivere un semplice script in Python che faccia il lavoro per me. Qualcuno che ho molto rispetto suggerito regex.

Edit:

Sì, LinkedHashMap. Così semplice, così facile e così non nelle specifiche di progettazione ora. Io odio la cascata. Lo odio con passione. Questa parte era una parte "piccola" e "facile" che "non dovrebbe richiedere molto tempo per progettare". Ho fatto degli errori. È bloccato nella pietra ora.

+4

Fammi capire bene: si dispone di una enorme massa ingestibile di codice Java piena di magia numeri e stringhe hardcoded e vuoi inserirne uno nel mezzo e incrementare i seguenti numeri usando python? – Jorenko

+0

Perché non usi una HashMap per questo? Basta usare la stringa come chiave e restituire il numero desiderato ... Mi sembra un modo più naturale per farlo. – Khelben

+0

@Jorenko: Sì e no.Le stringhe sono prese da documenti proprietari proprietari formattati che vengono passati alla nostra applicazione. Il codice non è enorme e non viola DRY. Tuttavia, hai ragione. Ci sono un sacco di numeri magici e sì, voglio inserirne uno nel mezzo. – wheaties

risposta

4

Vuoi che la tua espressione regolare sia flessibile come il compilatore rispetto agli spazi bianchi tra token. Farlo e imitare l'uso degli spazi bianchi rende il pattern piuttosto disordinato. Il codice qui sotto (mi dispiace: Perl, non Python) modifica i file sorgente sul posto.

#! /usr/bin/perl -i.bak  
use warnings; 
use strict; 
my $template = 
    '^(public 
     String 
     Get)(\w+)(\(\) { return 
     m_ParsedValue . get \(m_Tags . get \()(\d+)(\) \) ; })$'; 
$template =~ s/ +/\\s*/g; 
$template =~ s/(\r?\n)+/\\s+/g; 
my $getter = qr/$template/x; 

die "Usage: $0 after new-name source ..\n" unless @ARGV >= 3; 
my $after = shift; 
my $add = shift; 
my $index; 
while (<>) { 
    unless (/$getter/) { 
    print; 
    next; 
    } 
    my($abc,$name,$lmno,$i,$xyz) = ($1,$2,$3,$4,$5); 
    if (defined $index) { 
    print join "" => $abc, $name, $lmno, ++$index, $xyz; 
    } 
    else { 
    if ($name eq $after) { 
     $index = $i; 
     print; print join "" => $abc, $add, $lmno, ++$index, $xyz; 
    } 
    else { print; } 
    } 
} 

Per esempio,

$ ./add-after Jane Foo code.java 
$ cat code.java 
Foo extends Bar{ 
    public Foo(){ 
     m_Tags.add("Jane"); 
     m_Tags.add("Bob"); 
     m_Tags.add("Jim"); 
    } 

    public String GetJane() { return m_ParsedValue.get(m_Tags.get(1)); } 
    public String GetFoo() { return m_ParsedValue.get(m_Tags.get(2)); } 
    public String GetBob() { return m_ParsedValue.get(m_Tags.get(3)); } 
    public String GetJim() { return m_ParsedValue.get(m_Tags.get(4)); } 
}
+0

Grazie mille. Posso mostrarlo a qualcuno che conosce perl e python. Saranno in grado di guidarmi indietro. – wheaties

+0

Prego. Sono contento che aiuti. –

4

Non farlo con regexp. Crea costanti simboliche (usando ad esempio un enum) che mappano i nomi ai numeri.

+0

Tecnicamente, se dovessi riprogettare dall'inizio avrei creato una variabile nominata per ogni componente, assegnandoli a una lista, e poi passato quella lista alle funzioni di analisi. Quindi non avrei bisogno di trattare tutti questi numeri magici. – wheaties

+0

Non hai bisogno di una riprogettazione. Basta aggiungere le costanti ora. Quindi avere lo script, se è necessario utilizzarlo, incrementare le costanti. – vy32

0

Sto facendo questo (beh, qualcosa di molto simile) in questo momento, ma utilizzando macro di Excel e VBA. Tutti i valori aziendali sono organizzati e ordinati in un foglio di calcolo. Devo solo fare clic su un pulsante per generare il codice appropriato per le celle selezionate, quindi copiare e incollare nell'IDE. Ancora meglio, ho diverse "colonne di codice" per ogni riga. Alcuni di loro generano query, alcune trasformazioni XSL e alcune procedure. Per una riga di dati aziendali, posso ottenere facilmente tutti e tre i tipi di codice generato.

Ho trovato che questo (ri-generare) è MOLTO più semplice della riformattazione del codice esistente che avevo.

+0

Sembra un incubo di un sistema. –

+0

@matt b: All'inizio lo pensavo anch'io. Gli analisti mantengono i dati aziendali nei fogli di calcolo (in realtà sono abbastanza ben organizzati), quindi posso facilmente prenderne una copia e quindi applicare i miei macro per ottenere un sacco di codice della piastra della caldaia che raramente richiede un ritocco manuale. È molto veloce per lo sviluppo e si adatta ESATTAMENTE ai requisiti aziendali - questo aiuta anche a trovare errori nei requisiti. – FrustratedWithFormsDesigner

4

Commenti su Bad-pratiche a parte - Ecco il codice che hai chiesto nella lingua che hai chiesto. La cosa migliore se si mantiene il sistema in questo modo, probabilmente sarebbe di generare automaticamente questi file java nel processo di compilazione stesso - si manterrà una lista di nomi in un file .txt nella directory. Questo script è adatto a farlo.

(Non sarà modificare i file, è genrate nuovi basato sul modello hai postato qui)

import re, sys 

template = """Foo extends Bar{ 
    public Foo(){ 
%s 
    } 

%s 
} 
""" 

tag_templ = """  m_Tags.add("%s");""" 
getter_templ = """ public String GetJane() { return m_ParsedValue.get(m_Tags.get(%d)); }""" 

def parse_names(filename): 
    data = open(filename).read() 
    names = re.findall(r'm_Tags\.add\("(.*?)"', data) 
    return names 

def create_file(filename, names): 
    tag_lines = [tag_templ % name for name in names] 
    getter_lines = [getter_templ % (i + 1) for i in range(len(names))] 
    code = template % ("\n".join(tag_lines), "\n".join(getter_lines)) 
    file = open(filename,"wt") 
    file.write(code) 
    file.close() 

def insert_name(after, new_name, names): 
    names.insert(names.index(after) + 1, new_name) 

if __name__ == "__main__": 
    if len(sys.argv) < 4: 
     sys.stderr.write("Usage: changer.py <filename> <name-before-insertion> <new-name>") 
     sys.exit(1) 
    filename, name_before, new_name = sys.argv[1:] 
    names = parse_names(filename) 
    insert_name(name_before, new_name, names) 
    create_file(filename, names) 
+0

Grazie per questo e grazie per non aver commentato i miei errori. Questa è davvero una grande idea. Ho cercato di passare ad un approccio più pragmatico (appena finito un programmatore pragmatico un mese fa). – wheaties

+0

Un modello è assolutamente la strada giusta da percorrere. Ma perché non fare un ulteriore passo avanti e utilizzare una vera libreria di template come Template Toolkit per Python? http://tt2.org/python/index.html – daotoad

+0

Per quale motivo non è necessario farlo in un esempio così semplice? Una delle motoste di Python è "semplice è meglio del complesso" - e anche per il codice reale, ci sono abbastanza buoni metodi di formattazione delle template nelle librerie standard stesse per giustificare le dipendenze esterne per un caso così semplice. – jsbueno