2015-06-10 7 views
13

Java java.util.regex.MatcherreplaceFirst(...)/replaceAll(...) API zwraca ciągi znaków, które (przy użyciu domyślnego rozmiaru sterty) mogą również spowodować KILKA dla danych wejściowych tak dużych jak 20-50M znaków. Te 2 metody można z łatwością przepisać na write na Writer s zamiast konstruować ukłucia, skutecznie eliminując jeden punkt awarii.Java: zastąpienie regex w dużych plikach

Matcher jest factory method jednak tylko przyjmuje CharSequence S, która również może wyrzucać OOME w przypadku korzystania z StringStringBuffer S/S/StringBuilder s.

Jak mogę zawinąć java.io.Reader zaimplementować interfejs CharSequence (biorąc pod uwagę fakt, że moje wyrażenia regularne mogą zawierać odwołania wstecznego)? Czy istnieje inne rozwiązanie, które może zastąpić wyrazy regularne w plikach i nie jest OOME-podatne na duże nakłady?

Innymi słowy, w jaki sposób mogę zaimplementować funkcjonalność podobną do GNU sed w Javie (jako że sed radzi sobie z plikami o rozmiarach nawet kilku terabajtów, jednocześnie oferując taką samą obsługę rozszerzonych wyrażeń regularnych)?

+2

Czy wystarczy zastąpić pojedynczą linię na raz, czy zastąpić "cały plik jednym zamiennikiem"? –

+0

'Pattern.matcher()' nie tworzy nowego ciągu. Obiekt 'Matcher' stworzony po prostu przytrzymaj odnośnik do CharSequence przekazanego. – nhahtdh

+7

' sed' obsługuje pliki na zasadzie line-by-line, co powoduje, że nie wymaga dużej ilości pamięci dla dużych plików (chyba że plik ma * bardzo * długie wiersze lub kod nakazuje mu zapamiętanie wielu rzeczy). Jeśli zrobisz to samo w Javie (czytać wiersz, pracować nad nim, drukować, czytać następną linię, płukać, powtarzać), będziesz potrzebował podobnej ilości pamięci. Przy okazji, możesz być zainteresowany [Unix4j] (https://code.google.com/p/unix4j/). – Wintermute

Odpowiedz

1

Od czego potrzebujesz to faktycznie zachowanie sed można wykonać go robiąc coś takiego:

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

kładę przykład bash, ale jeśli chcesz, aby go uruchomić w systemie Windows można zainstalować polecenie sed przez Cygwin i wykonać taki sam lub po prostu zainstalować sed polecenia systemu Windows, które można pobrać stąd:

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

do okien można użyć:

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

I nie ma okien, więc nie mogę sprawdzić powyższe polecenie, to może trzeba usunąć call lub zmienić call po prostu sed. Inną alternatywą można spróbować to:

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

W tym link można znaleźć dir przykład wykonana z java można przystosować go do używania SED.

+0

Dzięki, to jest świetne rozwiązanie, ale potrzebuję mojego kodu, aby móc pracować na maszynach Windows bez żadnego Cygwina. – Bass

+0

@ Możesz też użyć 'sed' w oknach. Zaktualizowałem odpowiedź za pomocą linku, aby ją zainstalować –