-2

I have a byte array which is filled by a serial port event and code is shown below:

private InputStream input = null; 
......
......
public void SerialEvent(SerialEvent se){
  if(se.getEventType == SerialPortEvent.DATA_AVAILABLE){
    int length = input.available();
    if(length > 0){
      byte[] array = new byte[length];
      int numBytes = input.read(array);
      String text = new String(array);
    }
  }
}

The variable text contains the below characters,

"\033[K", "\033[m",  "\033[H2J", "\033[6;1H" ,"\033[?12l", "\033[?25h", "\033[5i", "\033[4i", "\033i" and similar types..

As of now, I use String.replace to remove all these characters from the string.

I have tried new String(array , 'CharSet'); //Tried with all CharSet options but I couldn't able to remove those.

Is there any way where I can remove those characters without using replace method?

7
  • Are you sure that the content you receive out of this port is a text-based at all? Commented May 27, 2014 at 10:20
  • @Oleg Estekhin I get [SquareSymbol] which is escape sequence \033 followed by whatever i have shown. e.g [Square][k like that. Commented May 27, 2014 at 10:22
  • input.available() is not a reliable way to check the number of bytes really available in the input stream, you should replace that part of code with the proper cycle over InputStream.read(byte[],int,int), otherwise you are reading incomplete chunks of data of random length. Commented May 27, 2014 at 10:33
  • And additionally input.read(array) is not guaranteed to read the full array, so your current code first fails to determine the number of bytes really available in the stream and then fail to read even that wrongly-determined amount of bytes. Commented May 27, 2014 at 10:36
  • @OlegEstekhin input.read(array, ?, ?) can u please give me a small example.. Or a link to start with. Commented May 27, 2014 at 10:39

1 Answer 1

0

I gave a unsatisfying answer, thanks to @OlegEstekhin for pointing that out. As noone else answered yet, and a solution is not a two-liner, here it goes.

Make a wrapping InputStream that throws away escape sequences. I have used a PushbackInputStream, where a partial sequence skipped, may still be pushed back for reading first. Here a FilterInputStream would suffice.

public class EscapeRemovingInputStream extends PushbackInputStream {

    public static void main(String[] args) {
        String s = "\u001B[kHello \u001B[H12JWorld!";
        byte[] buf = s.getBytes(StandardCharsets.ISO_8859_1);
        ByteArrayInputStream bais = new ByteArrayInputStream(buf);
        EscapeRemovingInputStream bin = new EscapeRemovingInputStream(bais);
        try (InputStreamReader in = new InputStreamReader(bin,
                StandardCharsets.ISO_8859_1)) {
            int c;
            while ((c = in.read()) != -1) {
                System.out.print((char) c);
            }
            System.out.println();
        } catch (IOException ex) {
            Logger.getLogger(EscapeRemovingInputStream.class.getName()).log(
                Level.SEVERE, null, ex);
        }
    }

    private static final Pattern ESCAPE_PATTERN = Pattern.compile(
        "\u001B\\[(k|m|H\\d+J|\\d+:\\d+H|\\?\\d+\\w|\\d*i)");
    private static final int MAX_ESCAPE_LENGTH = 20;

    private final byte[] escapeSequence = new byte[MAX_ESCAPE_LENGTH];
    private int escapeLength = 0;
    private boolean eof = false;

    public EscapeRemovingInputStream(InputStream in) {
        this(in, MAX_ESCAPE_LENGTH);
    }

    @Override
    public int read(byte[] b, int off, int len) throws IOException {
        for (int i = 0; i < len; ++i) {
            int c = read();
            if (c == -1) {
                return i == 0 ? -1 : i;
            }
            b[off + i] = (byte) c;
        }
        return len;
    }

    @Override
    public int read() throws IOException {
        int c = eof ? -1 : super.read();
        if (c == -1) { // Throw away a trailing half escape sequence.
            eof = true;
            return c;
        }
        if (escapeLength == 0 && c != 0x1B) {
            return c;
        } else {
            escapeSequence[escapeLength] = (byte) c;
            ++escapeLength;
            String esc = new String(escapeSequence, 0, escapeLength,
                    StandardCharsets.ISO_8859_1);
            if (ESCAPE_PATTERN.matcher(esc).matches()) {
                escapeLength = 0;
            } else if (escapeLength == MAX_ESCAPE_LENGTH) {
                escapeLength = 0;
                unread(escapeSequence);
                return super.read(); // No longer registering the escape
            }
            return read();
        }
    }

}
  • User calls EscapeRemovingInputStream.read
  • this read may call some read's itself to fill an byte buffer escapeSequence
  • (a push-back may be done calling unread)
  • the original read returns.

The recognition of an escape sequence seems grammatical: command letter, numerical argument(s). Hence I use a regular expression.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.