Java: поиск и замена в потоке - PullRequest
3 голосов
/ 26 октября 2009

Как выполнить поиск и замену на лету в потоке Java (вход или выход)?

Я не хочу загружать поток в память или в файл.

Я просто вижу, как проходят байты, и мне нужно сделать некоторые замены. Заменяемые последовательности короткие (до 20 байтов).

Ответы [ 3 ]

4 голосов
/ 26 октября 2009

Вы можете использовать предоставленный класс здесь , если вам достаточно статических правил замены.

1 голос
/ 26 октября 2009

Вы могли бы реализовать детерминированный конечный автомат , который просматривает каждый байт только один раз (например, просмотр не требуется), так что вы в основном будете передавать поток через буфер, содержащий максимум столько символов, сколько длина вашего шаблона, выводя шаблон на совпадение или переполняющиеся (не совпадающие) символы при продвижении в шаблоне. Время выполнения линейно после подготовки шаблона.

В Википедии есть некоторая информация о сопоставлении с образцом и о том, как это работает в теории.

0 голосов
/ 31 июля 2012

Я получил несколько хороших идей по предоставленной ссылке и в итоге написал небольшой класс для обработки замены переменных $ VAR $ в потоке. Для потомков:

public class ReplacingOutputStream extends OutputStream {
    private static final int DOLLAR_SIGN = "$".codePointAt(0);
    private static final int BACKSLASH = "\\".codePointAt(0);
    private final OutputStream delegate;
    private final Map<String, Object> replacementValues;

    private int previous = Integer.MIN_VALUE;
    private boolean replacing = false;
    private ArrayList<Integer> replacement = new ArrayList<Integer>();


    public ReplacingOutputStream(OutputStream delegate, Map<String, Object> replacementValues) {
        this.delegate = delegate;
        this.replacementValues = replacementValues;
    }

    public @Override void write(int b) throws IOException {
        if (b == DOLLAR_SIGN && previous != BACKSLASH) {
            if (replacing) {
                doReplacement();
                replacing = false;
            } else {
                replacing = true;
            }
        } else {
            if (replacing) {
                replacement.add(b);
            } else {
                delegate.write(b);
            }
        }

        previous = b;
    }

    private void doReplacement() throws IOException {
        StringBuilder sb = new StringBuilder();
        for (Integer intval : replacement) {
            sb.append(Character.toChars(intval));
        }
        replacement.clear();

        String oldValue = sb.toString();
        Object _newValue = replacementValues.get(oldValue);
        if (_newValue == null) {
            throw new RuntimeException("Could not find replacement variable for value '"+oldValue+"'.");
        }

        String newValue = _newValue.toString();
        for (int i=0; i < newValue.length(); ++i) {
            int value = newValue.codePointAt(i);
            delegate.write(value);
        }
    }
}
...