2015-06-10 15 views
13

Java java.util.regex.Matcher /replaceAll(...) API restituisce stringhe, che (se si utilizza la dimensione heap predefinita) potrebbero causare un OOME per input grandi come 20-50M caratteri. Questi 2 metodi possono essere facilmente riscritti a write a Writer s piuttosto che costruire punture, eliminando efficacemente un punto di errore.Java: regex replacement in file di grandi dimensioni

s' The Matcherfactory method, tuttavia, accetta solo CharSequence s, che è anche in grado di lanciare un OOME se uso String s/s/StringBufferStringBuilder s.

Come posso avvolgere un java.io.Reader ad implementare un'interfaccia CharSequence (in considerazione del fatto che le mie espressioni regolari possono contenere backreference)? C'è qualche altra soluzione che possa sostituire espressioni regolari nei file e non sia soggetta a OOME su input di grandi dimensioni?

In altre parole, come faccio a implementare una funzionalità simile a quella di GNU sed in Java (come sed è noto per affrontare i file grandi come un paio di terabyte, mentre con lo stesso supporto per le espressioni regolari estese)?

+2

Avete solo bisogno di sostituire una singola riga alla volta, o sostenere "tutto il file in una volta sola" sostituzioni? –

+0

'Pattern.matcher()' non crea una nuova stringa. L'oggetto 'Matcher' creato basta tenere un riferimento al CharSequence passata. – nhahtdh

+7

' sed' gestisce i file con il metodo dell'integrazione globale, che è il motivo per cui non richiede un sacco di memoria per file di grandi dimensioni (a meno che il il file ha * molto * lunghe righe o il codice lo istruisce per ricordare un sacco di cose). Se fai lo stesso in Java (ad esempio, leggi una riga, lavoraci sopra, stampala, leggi la riga successiva, risciacqua, ripeti), avrai bisogno di una quantità di memoria simile. A proposito, potresti essere interessato a [Unix4j] (https://code.google.com/p/unix4j/). – Wintermute

risposta

1

Dal momento che ciò che è necessario è in realtà il comportamento sed è possibile eseguirlo facendo qualcosa di simile a questo:

String[] cmdArray = {"bash", "-c", "sed 's/YourRegex/YourReplaceStr/' inputfile > output"}; 
Process runCmd = Runtime.getRuntime().exec(cmdArray); 

ho messo un esempio bash, ma se si desidera eseguire su Windows è possibile installare sed comando attraverso Cygwin ed eseguire lo stesso o è sufficiente installare il comando sed per le finestre che potete scaricare da qui:

http://gnuwin32.sourceforge.net/packages/sed.htm

per le finestre è possibile utilizzare:

String[] cmdArray = {"call", "sed 's/YourRegex/YourReplaceStr/' inputfile > output"}; 
Process runCmd = Runtime.getRuntime().exec(cmdArray); 

Non ho le finestre in modo da non può provare sopra di comando, è forse necessario rimuovere call o per modificare il call ad appena sed. Un'altra alternativa si può provare è:

String[] cmdArray = {"cmd", "/c", "sed 's/YourRegex/YourReplaceStr/' inputfile > output"}; 
Process runCmd = Runtime.getRuntime().exec(cmdArray); 

In questo link si può trovare un esempio dir eseguito da Java è possibile adattarlo a usare sed.

+0

Grazie, questa è un'ottima soluzione, ma ho bisogno che il mio codice sia in grado di funzionare anche su macchine Windows senza Cygwin. – Bass

+0

@Bass puoi usare 'sed' anche in Windows. Ho aggiornato la risposta con un link per installarlo –

Problemi correlati