【问题标题】:replacing text in a printstream替换打印流中的文本
【发布时间】:2012-07-31 15:05:30
【问题描述】:

是否可以在打印流中替换正则表达式?

我有一段代码记录了我的控制台窗口中显示的所有文本,但它也记录了 ANSI 转义码。

我发现这个正则表达式 "s:\x1B\[[0-9;]*[mK]::g" 可以删除它们,但它只适用于字符串。 有没有办法将正则表达式替换应用于恒定的字符串流并过滤掉 ANSI 转义码?

如果可能的话,尽可能地简化它,在编程方面我还是一个新手,我只是在一个已经有的程序上构建。

编辑:

我有这段代码,我在其他地方发现堆栈溢出,这允许我同时流式传输到日志文件和控制台。

这就是我使用的,然后我在这之后设置了发球台。

Logging tee = new Logging(file, System.out);

.

package com.md_5.mc.chat;

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;

public class Logging extends PrintStream
{
  private final PrintStream second;

  public Logging(OutputStream main, PrintStream second)
  {
    super(main);
    this.second = second;
  }

  public void close()
  {
    super.close();
  }

  public void flush()
  {
    super.flush();
    this.second.flush();
  }

  public void write(byte[] buf, int off, int len)
  {
    super.write(buf, off, len);
    this.second.write(buf, off, len);
  }

  public void write(int b)
  {
    super.write(b);
    this.second.write(b);
  }

  public void write(byte[] b) throws IOException
  {
    super.write(b);
    this.second.write(b);
  }
}

【问题讨论】:

  • 那你的问题现在解决了吗?如果是这样,理想情况下,您应该将其重新发布为答案并将其标记为已接受。如果不是,您能否解释一下这对您的问题有何影响?
  • @DuncanJones 这是我已经存在的代码,我只是不知道如何编辑打印流 (System.out) 以将 ANSI 代码从输出流中过滤到我的文件中。
  • 我假设,其他假设,您想要一个过滤掉 ANSI 的 PrintStream(如开头所述)。然后在编辑中它谈论您正在使用的其他代码(恰好进行输出重复)。所以只是为了确定:你想让你的代码(打印到两个输出)也过滤掉一个正则表达式。不是吗? (也许应该从一开始就说得更清楚)

标签: java regex replace printstream


【解决方案1】:

Create 创建FilterOutputStream 的子类,例如RegexOutputStream。这个类应该缓冲所有写入它的数据(来自不同的write(...) 方法)。在flush() 方法中,它应该应用正则表达式,然后将结果写入底层OutputStream

接下来,实例化PrintWriter 以写入RegexOutputStream。这样您就不需要更改PrintWriter 类的行为。如果您不再需要过滤,您可以将 RegexOutStream 移出链,一切都会再次运行。

请注意,根据您使用PrintWriter 的方式,这可能会导致RegexOutputStreams 缓冲区变得非常大。如果您创建 PrintWriter 来自动刷新,它将在每一行和每个字节数组之后刷新。详情请见其JavaDoc

【讨论】:

  • 这个想法(实现为 FilterOutputStream)是正确的,但请求者要求更多的东西(新手)。我碰巧也有同样的想法。
【解决方案2】:

您可以在调用适当的super 方法之前对有问题的打印流进行子类化并执行正则表达式替换?例如

public void ExampleStream extends PrintStream {

  @Override
  public void print(String s) {
    super(s.replaceAll(ANSI_PATTERN,""));
  }
}

【讨论】:

  • 印刷和书写有很多种风格。 print(String) 和其他 print() 方法委托 write(String)。如果你重新定义 write(String) 会更好,但如果使用 print(char[]) 就不够好了(例如)。
  • 糟糕,对不起,我编辑了答案,我的意思是在我自己的编辑中将文字变成常量。我无法还原它。
  • @Javier 没问题,它改进了我的答案。
【解决方案3】:

我认为Logging 类中的代码不是一个好方法(至少现在是这样):

  • 如果您有权访问 PrintStream 源代码,您可能会发现当前重新定义的方法可能根本没有被使用: PrintStream#print(...) 方法委托于 textOut#write(...)(不在重新定义的 OutputStream#write(...) )。
  • 因此,您应该重新定义 print(String) 和 print(char[]) 方法以有效过滤输出。
  • 在答案中有一些重新定义方法的示例(包括在此更下方的方法)。

或者,如果您只想要一个过滤掉 ANSI 代码的 PrintStream(正如我最初理解的那样),那么在 FilterOutputStream 上实现它会更方便(正如 mthmulders 所建议的那样,因为您将不得不重新定义更少的东西和将更容易重复使用):

  • 复制BufferedOutputStream 类。随意命名。 (例如 TrimAnsiBufferedStream
  • 然后重新定义de flushBuffer()方法:

    private void flushBuffer() throws IOException {
        if (count > 0) {
            String s = new String(buf, 0, count); // Uses system encoding.
            s.replaceAll(ANSI_PATTERN, "");
            out.write(s.getBytes());
            count = 0;
        }
    }
    
  • 当您需要实例化替代 ANSI 的 PrintStream 时,调用 new PrintStream(new TrimAnsiBufferedStream(nestedStream))

  • 这可能不是万无一失的(例如,编码配置可能发生的任何事情,或者缓冲区大小不够大,或者打印流中的刷新选项),但我不会让它过于复杂。

顺便说一句。欢迎 kukelekuuk00。请务必阅读常见问题解答和对答案的反馈(我们关心您,请回报)。

【讨论】:

  • 我很难理解如何做到这一点,我对编程很陌生,而且我没有做过太多的 java 编程。我制作了 BufferedOutputStream (pastie.org/4366500) 的副本,但我真的不知道我是否做得对以及如何使用它。谢谢你,我会的。
  • @kukelekuuk00 我不知道如何进一步解释。虽然我可能会剥夺你解决问题的机会,但你有课程的代码:(pastie.org/4366578)。希望有帮助
  • 我会仔细看看你做了什么,然后继续。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多