2015-12-11 22 views
7

I dati per le attività sono state registrate con un'app time sheet. Sto cercando di analizzare le interruzioni per ogni attività.Timestamp di raggruppamento con descrizioni

Una stringa esempio pausa attaccato ad un compito può apparire come segue:

13:19-22:33 mangiato tacos 22:35-23:38 00:40-01:24 ha preso un pisolino

Ho bisogno di raggruppare questo in timestamp con le loro descrizioni associate. Quanto sopra dovrebbe essere raggruppati come:

13:19-22:33 tacos mangiato

22:35-23:38

00:40-01:24 ha preso un pisolino

La descrizione per un intervallo di interruzione può avere praticamente qualsiasi carattere o essere di qualsiasi lunghezza. Alcuni intervalli non hanno descrizioni.

I figura regex sarebbe il modo più semplice per ottenere una serie di intervalli con le loro descrizioni (se ne hanno uno).

Finora ho:

\d{1,2}:\d{2}[ap]m\s–\s\d{1,2}:\d{2}[ap]m 

che corrisponde ai timestamp 1:19pm – 10:33pm, 10:35pm – 11:38pm, e 12:40am – 1:24am

Sto usando JavaScript, e la funzione match, per analizzare questi dati. Voglio fare un'espressione regolare che corrisponda al timestamp e tutto ciò che lo segue fino al prossimo timestamp.

Sono un principiante con regex quindi andate piano con me. Sono stato a questo per ore, guardato diversi video, leggere blog tutorial, e ho sperimentato con regex101. Le ancore, lookahead/behinds, sono confuse e non riesco a ottenere nulla per fare ciò che voglio. Non sto cercando di diventare un esperto nella scrittura di espressioni regolari, ma mi piacerebbe davvero imparare qualcosa di nuovo che possa essere applicato direttamente a ciò che sto facendo.

risposta

5

È possibile utilizzare la seguente espressione regolare:

(\d{1,2}:\d{2}[ap]m\s*–\s*\d{1,2}:\d{2}[ap]m)(\D*(?:\d(?!\d?:\d{2}[ap]m\s)\D*)*) 

Vedere le regex demo

Il problema che si deve affrontare è corrispondente a un testo che fa n o abbinare un modello specifico. Ciò può essere ottenuto con un token goloso o con una unroll-the-loop tecnica. Quest'ultimo è preferibile in quanto comporta un minor backtracking. Il mio regex è basato su quella tecnica.

Ecco la spiegazione regex:

  • (\d{1,2}:\d{2}[ap]m\s*–\s*\d{1,2}:\d{2}[ap]m) - partite e cattura in gruppo # 1 periodo di tempo (ho solo aggiunto parentesi esterne e le * quantificatori per \s classi) - come è il tuo regex, Non entrerò nei dettagli
  • (\D*(?:\d(?!\d?:\d{2}[ap]m\s)\D*)*) - si tratta di un costrutto .*?(?=\d{1,2}:\d{2}[ap]m\s) srotolato che combacia fino al primo modello \d{1,2}:\d{2}[ap]m\s. È inserito nel gruppo n.
    • \D* - 0 o più caratteri diversi dal cifre
    • (?:\d(?!\d?:\d{2}[ap]m\s)\D*)* - 0 o più sequenze di ...
      • \d(?!\d?:\d{2}[ap]m\s) - una cifra (\d) che non è seguito da 1 o 0 cifre seguite con : seguito con 2 cifre, quindi a o p, poi m, e quindi uno spazio bianco
      • \D* - nuovo, 0 o più caratteri diversi una cifra.

JS demo:

var re = /(\d{1,2}:\d{2}[ap]m\s*–\s*\d{1,2}:\d{2}[ap]m)(\D*(?:\d(?!\d?:\d{2}[ap]m\s)\D*)*)/ig; 
 
var str = '1:19pm – 10:33pm ate tacos 10:35pm – 11:38pm 12:40am – 1:24am took a nap'; 
 
var m; 
 
    
 
while ((m = re.exec(str)) !== null) { 
 
    document.getElementById("r").innerHTML += "Period: " + m[1] + "<br/>"; 
 
    document.getElementById("r").innerHTML += "Description: " + m[2] + "<br/><br/>"; 
 
}
<div id="r"/>

+1

Pensavo che fossi interessato a organizzare l'output in una forma più leggibile, quindi ho suggerito due gruppi di cattura. Nota che l'altra soluzione funzionante sta usando un costrutto che può portare a un backtrack catastrofico se il tuo input è ampio. Le espressioni regolari Srotolare il ciclo non sono così soggette a questo problema. –

+0

Hai finito questa discussione, che bella risposta. – jgoodhcg

+1

Si noti che nel caso in cui il modello regex sia noto in anticipo, la tecnica [* srotolare-il-ciclo * (o * Alternated Star Alternation Solution *)] (http://www.rexegg.com/regex-quantifiers.html#unrolled_staralt) è il più appropriato per corrispondere fino all'occorrenza più vicina di un subpattern. Nel caso si utilizzi una variabile, è necessario utilizzare un [* token greedy temperato *] (http://www.rexegg.com/regex-quantifiers.html#tempered_greed) o una soluzione non regex se non è efficiente abbastanza. –

2

auguriamo che contribuiscano:

https://regex101.com/r/dV7vY5/1

(\ d {1,2}: \ d {2} [AP] m) - (\ d {1,2}: \ d {2} [AP] m) ([\ s | az | AZ] +)

uscita:

13:19-22:33 mangiato tacos

012.351.

22:35-23:38

00:40-01:24 ha preso un pisolino

e si può acess ogni picchiettio:

$1 - first hour (1:19pm) 
$2 - second hour (10:33pm) 
$3 - string  (ate tacos) 

esempio qui sotto:

var string = '1:19pm – 10:33pm ate tacos 10:35pm – 11:38pm 12:40am – 1:24am took a nap'; 
 
var regex = /(\d{1,2}:\d{2}[ap]m) – (\d{1,2}:\d{2}[ap]m)([\s|a-z|A-Z]+)/gi; 
 
var eachMatche = string.match(regex); 
 

 
for (var i = 0; i < eachMatche.length; i++) { 
 
    snippet.log(eachMatche[i]); 
 
    snippet.log('period : '+ eachMatche[i].replace(regex,'$1') +' - ' + eachMatche[i].replace(regex,'$2')); 
 
    snippet.log('description : '+eachMatche[i].replace(regex,'$3')); 
 
}
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

+2

Che cosa succede se la descrizione contiene caratteri Unicode? Puoi solo abbinare lettere ASCII, letterali '|', e spazi bianchi ora con '[\ s | a-z | A-Z]'. –

+0

buon punto! Immagino che sia solo migliorare per questa situazione! se hai la risposta aggiorna il mio codice. :) grazie @stribizhev –

+0

Ho fornito la mia risposta. –

4

Sono sicuro che questo può essere semplificata, ma la seguente espressione regolare sembra funzionare:

Example Here

/(\d{1,2}:\d{2}[ap]m\s–\s\d{1,2}:\d{2}[ap]m(?:.(?!\d{1,2}:\d{2}[ap]m))*)/g 

var input = '1:19pm – 10:33pm ate tacos 10:35pm – 11:38pm 12:40am – 1:24am took a nap'; 
 
var matches = input.match(/(\d{1,2}:\d{2}[ap]m\s–\s\d{1,2}:\d{2}[ap]m(?:.(?!\d{1,2}:\d{2}[ap]m))*)/g); 
 

 
for (var i = 0; i < matches.length; i++) { 
 
    snippet.log(matches[i]); 
 
}
<script src="http://tjcrowder.github.io/simple-snippets-console/snippet.js"></script>

uscita:

13:19 - 22:33 mangiato tacos

22:35-23:38

00:40-01:24 ha preso un pisolino

+1

Si sta utilizzando un costrutto simile a un token goloso temperato. La mia regex basata sulla srotolare la tecnica loop è molto più efficiente perché non prova ogni carattere, e funziona con contenuti multilinea senza ulteriori ritocchi. Il tuo '(?:. (?! \ D {1,2}: \ d {2} [ap] m)) *' si soffocherà su una nuova riga. –

+0

@stribizhev L'ho preso; il tuo è chiaramente migliore Io non sono un esperto di regex come te :) –

+0

Ancora, la maggior parte della gente pensa che una regex deve essere leggibile, non efficiente, quindi spesso "perdo" i marchi accettati :) –