2009-10-02 10 views
7

Ho trovato un sacco di esempi su per sostituire il testo nei file usando espressioni regolari. Tuttavia, tutto si riduce a due versioni:
1. Iterare su tutte le righe nel file e applicare regex a ciascuna singola riga
2. Caricare l'intero file.Ricerca regex multilinea nell'intero file

n ° 2 non è fattibile con i "miei" file - sono circa 2GiB ...
Quanto al n ° 1: Attualmente questo è il mio approccio, però mi chiedevo ... cosa succede se necessità di applicare una regex che copre più di una linea?

+1

È possibile caricare questi dati in un RDBMS? –

+0

Penso che avrai bisogno di descrivere i tuoi dati e regex meglio per ottenere un suggerimento decente. –

+0

ok. Piccolo chiarimento: spesso ho bisogno di modificare grandi file CSV. (ad esempio switch col 3 e 5) Ho scoperto che, usando regex e sed, posso applicare le modifiche necessarie molto velocemente. Tuttavia, "sviluppo" e collaudo la mia regex usando Regolatore, che si tradurrà in "clr-regex" che poi devono essere tradotte in sed-syntax. Per evitare questo ho scritto un piccolo strumento (C#), che mi permette di applicare "clr-regex" a un file. ORA: con questo strumento non è possibile applicare espressioni regolari che coprano più di una riga, poiché sto facendo l'approccio sopra menzionato n. 1. La domanda di cui sopra era in qualche modo ipotetica. – Nils

risposta

2

Ecco la risposta:
Non v'è alcun modo semplice

Ho trovato un StreamRegex-Class che potrebbe essere in grado di fare ciò che sto cercando.
Da quello che ho potuto cogliere dell'algoritmo:

  • Inizia all'inizio del file con un buffer vuoto
  • do (
    • aggiungere un pezzo del file al buffer
    • se c'è una corrispondenza nel buffer
      • contrassegnare la partita
      • eliminare tutti i dati che è apparso prima della fine della partita dal buffer
  • ), mentre c'è ancora qualcosa del file sinistra

In questo modo non è nessesary per caricare il file completo - o almeno le possibilità di caricare l'intero file in memoria sono ridotte ...
Tuttavia: il caso peggiore è che non c'è corrispondenza nell'intero file - in questo caso il file completo verrà caricato in memoria.

0

Forse potresti caricare 2 linee per volta (o più, a seconda di quante linee pensi che le tue corrispondenze debbano estendersi) e sovrapporle, ad esempio: caricamento delle linee 1-2, quindi del prossimo ciclo di carico linee 2-3, il prossimo carico 3-4; e fai le tue regex multiline su entrambe le linee combinate, in ogni ciclo.

+0

Buona idea, comunque ogni riga sarebbe stata regex'd forse più volte. Uno dovrebbe prendere in considerazione i possibili effetti collaterali .. – Nils

+0

Hmm sì, hai ragione. Forse abbinare solo quando la partita inizia sulla prima riga (prima di qualsiasi istanza di interruzione di riga)? –

1

Regex non è la strada da percorrere, specialmente con queste grandi quantità di testo. Creare un parser personale:

  • leggere il file riga per riga;
  • per ogni linea:
    • ciclo attraverso la linea di carattere, mantenendo char traccia di qualsiasi apertura/chiusura stringhe letterali
    • quando si incontra '/ *' (e non sei 'dentro' una stringa), negozio che compensato numero e ciclo fino a quando si incontra la prima '* /' e memorizzare questo numero così

che vi darà tutte le starting- e numbe chiusura-offset rs dei blocchi di commento. Ora dovresti essere in grado di sostituirli creando un file temporaneo e scrivendo il testo dal file originale al file temporaneo (e scrivendo qualcos'altro se sei all'interno di un blocco di commenti, ovviamente).

Modifica: file sorgente di 2GiB ??

+0

Ho detto fonte? ;-) Nessun dato "grezzo", csv in effetti. – Nils

+0

Ah, capisco. Non so C#, ma immagino che non sarebbe nemmeno possibile creare file di origine così grandi. –

0

Direi che è necessario eseguire la pre-analisi/normalizzazione dei dati prima di eseguire le sostituzioni in modo che ogni riga descriva una possibile serie di dati a cui è necessario applicare le sostituzioni. In caso contrario, si incorre in complicazioni con l'integrità dei dati che non possono essere risolti senza una serie di altre difficoltà.

Se esiste un modo per dividere i dati in blocchi logici, è possibile creare un programma che utilizza uno schema di ridimensionamento della mappa per analizzare i dati.

0

Sono con Bart; dovresti davvero usare una specie di parser per questo.

O, se non ti dispiace generando un processo figlio, si potrebbe utilizzare sed (c'è un native port on windows, oppure è possibile utilizzare Cygwin)

0

Se non ti dispiace sporcarti un po 'le mani (e la tua espressione regolare è abbastanza semplice, o forse hai un forte desiderio di velocità e non ti dispiace soffrire un po'), puoi usare Ragel. Può indirizzare C#, anche se il sito non lo menziona. Avrai bisogno di avvolgere un FileStream per fornire un indicizzatore bufferizzato o utilizzare un file mappato in memoria (con puntatori non sicuri) in un processo a 64 bit per utilizzarlo comunque con file di grandi dimensioni.