2012-04-29 12 views
5

Sto analizzando il testo che è molte ripetizioni di un modello semplice. Il testo è nel formato di una sceneggiatura per un gioco, come questo:Espressione regolare per abbinare tutti i personaggi fino alla corrispondenza successiva

SAMPSON 
I mean, an we be in choler, we'll draw. 

GREGORY 
Ay, while you live, draw your neck out o' the collar. 

Attualmente sto usando il modello ([A-Z0-9\s]+)\s*\:?\s*[\r\n](.+)[\r\n]{2}, che funziona bene (spiegazione di seguito) tranne quando il discorso del personaggio ha interruzioni di riga in esso . Quando ciò accade, il nome del personaggio viene catturato con successo ma viene catturata solo la prima riga del discorso.

L'attivazione della modalità a linea singola (per includere interruzioni di linea in .) crea una corrispondenza gigantesca.

Come posso dire allo (.+) di fermarsi quando trova il nome del personaggio successivo e terminare la partita?
Sto iterando su ogni singola partita (JavaScript), quindi il nome deve essere disponibile per la prossima partita.

Idealmente, sarei in grado di abbinare tutti i caratteri fino a quando l'intero schema non viene ripetuto.


modello ha spiegato:

Il primo gruppo corrisponde al nome di un personaggio (che permette lettere maiuscole, numeri e spazi bianchi), (con i due punti finali e gli spazi opzionale).
Il secondo gruppo (il discorso del personaggio) inizia su una nuova riga e cattura qualsiasi carattere (tranne, in modo problematico, interruzioni di riga e caratteri dopo di essi).
Il motivo termina (e ricomincia) dopo una riga vuota.

+0

È necessario definire in modo inequivocabile come si determina dove il nome successivo inizia prima di poter scritto e una regex per abbinarla. È una parola singola seguita da due punti su una riga da sola? Questo si tradurrebbe in partite errate? – mellamokb

+0

@mellamokb Ho dimenticato di includere l'ultima parte del pattern, che cerca una riga vuota. La partita inizia dal nome del personaggio (tutte le maiuscole sulla sua stessa riga) e termina nella riga vuota dopo il discorso. – Nathan

+0

Credo che manchi i due punti nel testo di esempio, la regex non funziona con esso. –

risposta

0

Ok, ho fatto un po 'di complicazioni e ho trovato qualcosa che funziona. Non è super elegante, ma fa il lavoro.

([A-Z0-9\s]+)\s*\:?\s*[\r\n]((.+[\r\n]?.*)+)[\r\n]{2} 

ho modificato l'ultimo gruppo di cattura per consentire infinite ripetizioni di testo arbitrario, una nuova linea, e il testo più arbitrario. Poiché non sono consentite due interruzioni di riga consecutive, il modello termina dopo il discorso.

+0

Volevo solo precisare, ho incollato la regex e l'esempio dalla tua domanda in [uno strumento di test regex] (http://gskinner.com/RegExr/) quindi abilitato semplicemente * dotall * mode (punti corrispondono alle nuove linee) che hanno risolto il tuo problema. È strano che non abbia funzionato per te – Hubro

1

Considerate di andare in una direzione diversa con questo. Vuoi davvero dividere un dialogo più grande su qualsiasi riga che contiene un nome. Si può fare questo con un'espressione regolare ancora (sostituire l'espressione regolare con qualunque corrisponderà alla linea "speaker"):

results = "Insert script here".split(/^([A-Z]+)$/) 

Su uno standard compatibile attuazione, è ad esempio il testo finirà in un array in questo modo:

results[0] = "" 
results[1] = "SAMPSON"  
results[2] = "I mean, an we be in choler, we'll draw.    
" 
results[3] = "GREGORY"  
results[4] = "Ay, while you live, draw your neck out o' the collar. " 

Un avvertimento è che la maggior parte dei browser sono chiazzati sullo standard qui. È possibile utilizzare la libreria XRegExp per ottenere il comportamento su più piattaforme.

+0

Nel mio caso d'uso, dividere i dialoghi in righe separate non ha senso. Dal momento che il programma (e l'utente) interagisce con le finestre di dialogo nel loro insieme, dovrei semplicemente ricollegarli insieme in modo che possano essere utili. – Nathan

0

Sono finalmente riuscito a farlo corrispondere solo a ciò che volevi, ad es.
- il nome del personaggio, consentendo spazi bianchi e il colon
- e, opzionalmente MULTILINE con linebreaks, il testo associato con la persona

si avrebbe bisogno di fare findAll usando questo regex - è case sensitive:

((?:[A-Z]{2,}\s*:?\s*)+)\s+((?![A-Z]{2,}\s*:?\s*).+?[.?!]\s*)+ 

Spiegazione:

  • ((?:[A-Z]{2,}\s*:?\s*)+) - il primo gruppo cattura il nome maiuscolo della persona - è corrisponderà 'GREGOR' così come 'MANFRED IL PIU' GRANDE:'
  • \s+ - almeno un carattere di spaziatura
    quindi ripetere almeno una volta:
  • (?![A-Z]{2,}\s*:?\s*) - guardare avanti per verificare che il testo successivo non è la parte superiore caso il nome del personaggio
  • .+?[.?!]\s* - abbinare tutto fino a trovare un personaggio che termina una frase [.?!] e opzionalmente spazi bianchi
Problemi correlati