【问题标题】:java: search & replace in a Streamjava:在流中搜索和替换
【发布时间】:2009-10-26 13:36:09
【问题描述】:

如何在 Java 流(输入或输出)中进行动态搜索和替换?

我不想将流加载到内存或文件中。

我只看到经过的字节,我需要做一些替换。被替换的序列很短(最多 20 个字节)。

【问题讨论】:

  • 这取决于它是什么样的“流”。是文字吗?它是某种具有已知字段宽度的格式吗?您的问题必须更加具体。
  • 这是二进制随机垃圾。
  • 替换是否和原来的“字符串”(字节序列)一样长?
  • @Lucero:没有。字符串和替换都比流短得多。但替换可以比原始字符串长、等长或短。
  • 这不是您问题的真正答案。不过,您应该查看 java.nio 包。请看以下示例:NIO Examples 第一个示例展示了如何对文件执行简单的“grep”。使用 NIO,您不必担心缓冲区大小,只需让正则表达式库方法完成繁重的工作。

标签: java regex io stream replace


【解决方案1】:

如果静态替换规则对你来说足够了,你可以使用here提供的类。

【讨论】:

  • 只是一个小的“学术”注释:我查看了源代码,据我所知,运行时/CPU 使用率——尤其是在最坏的情况下——似乎非常糟糕。假设例如 10 个 101 个字符的模式,对于 每个 字节的读取,可能会执行多达 1000 个处理步骤(比较操作)。 DFA 解决方案只需要一项操作(查表)。随着模式大小和数量以及输入流长度的增加,这可能会成为一个问题。
  • (但是,源代码在结构和文档方面做得很好,并且测试覆盖率很好,所以请把我的评论作为对更好算法的建议,我并不是要批评答案.)
  • 谢谢,在这里引用该课程的原因之一是能够获得反馈:) 您的评论是正确的,将修改算法。
  • 这可能应该直接指向issues.apache.org/jira/browse/IO-218 提出它的地方(更稳定的链接源,因为它无论如何取决于apache commons-io)。
【解决方案2】:

您可以实现一个deterministic finite automaton,它只查看每个字节一次(例如,不需要后视),这样您基本上可以通过一个缓冲区流式传输输入,该缓冲区最多可容纳与您的模式长度一样多的字符,输出模式上的匹配或在模式中前进时溢出(非匹配)字符。准备好模式后,运行时间是线性的。

理论上,维基百科有一些关于pattern matching and how that works 的信息。

【讨论】:

  • 谢谢你,@Lucero。我正在寻找图书馆解决方案。
【解决方案3】:

我从提供的链接中得到了一些好主意,最后编写了一个小类来处理流中 $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);
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-13
    • 1970-01-01
    • 2010-12-13
    • 2015-08-18
    • 2010-10-06
    • 2011-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多