Преобразуйте java.io.Reader в другой Reader, пропустив чтение некоторых символов

У меня есть java.io.Reader в качестве входного параметра метода.

Эта программа чтения читает файл, например "abc\def\jhk"; Мне нужно вернуть из метода другой java.io.Reader, который пропускает чтение "\" символов. Итак, окончательный файл должен быть: "abcdefjhk".

private Reader convertToFilteredReader(Reader reader) {
    Reader filteredReader = null;
    // some code here
    return filteredReader;
}

Я выполнил эту задачу, преобразовав Reader в String, вызвав String.replace('\', '') и затем преобразовав это String в Reader. Но мне это решение не нравится из-за двойной конвертации (Reader -> String -> Reader).

возможно, вариант использования FilterReader

user85421 25.06.2024 19:48

Как насчет того, чтобы попробовать функцию замены регулярного выражения?

SELA 25.06.2024 19:56

@user85421 на высоте

g00se 25.06.2024 22:52

Да, @Sören, правильно, для меня проблема не в том, как внести изменения в String, а в том, как не использовать String в этом процессе.

Volodymyr Patriiuk 25.06.2024 22:53
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
4
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуйте это. Отказ от ответственности: проверено только поверхностно. Комментарии показывают, насколько легко это использовать повторно.

import java.io.StringReader;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Path;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.FilterReader;
import java.io.IOException;
import java.io.Reader;

/**
 * Subclasses should implement isExcluded to determine which characters will be
 * 'swallowed' by the Reader
 *
 * @author g00se
 * @version 1.0
 */
public abstract class ExclusionReader extends FilterReader {
    private char[] singleCharBuf = { 0 };

    public ExclusionReader(Reader in) {
        super(in);
    }

    // Testing only
    public static void main(String[] args) throws IOException {
        Reader downstream = args.length < 1 ? new StringReader("abc\\def\\ghi")
                : Files.newBufferedReader(Path.of(args[0]));
        try (Reader in = new BackslashExcludingReader(downstream);
                Writer out = new OutputStreamWriter(System.out)) {
            in.transferTo(out);
        }
    }

    public abstract boolean isExcluded(int codePoint);

    @Override
    public int read() throws IOException {
        int result = read(singleCharBuf, 0, 1);
        return result > -1 ? singleCharBuf[0] : result;
    }

    @Override
    public int read(char[] b) throws IOException {
        return read(b, 0, b.length);
    }

    @Override
    public int read(char[] buf, int off, int len) throws IOException {
        if (len <= 0) {
            if (len < 0) {
                throw new IndexOutOfBoundsException();
            } else if ((off < 0) || (off > buf.length)) {
                throw new IndexOutOfBoundsException();
            }
            return 0;
        }
        int charsCopied = 0;
        int c = -1;

        while ((charsCopied + off) < len && (c = in.read()) > -1) {
            if (!isExcluded(c)) {
                buf[off + charsCopied] = (char) c;
                charsCopied++;
            }
        }

        int returnVal = charsCopied;
        if (charsCopied == 0) {
            returnVal = Math.min(charsCopied, c);
        }
        return returnVal;
    }

    // What YOU need
    static class BackslashExcludingReader extends ExclusionReader {
        public BackslashExcludingReader(Reader in) {
            super(in);
        }

        @Override
        public boolean isExcluded(int codePoint) {
            return codePoint == '\\';
        }

    }
}

Кстати, нет необходимости переопределять read(char[]) (тот же код уже есть в Reader)

user85421 25.06.2024 23:17

@ user85421 - верно, да

g00se 25.06.2024 23:29

Лучший способ справиться с этим — использовать FilterReader, который отфильтровывает спецификации. Они существуют. iirc, в Commons IO может быть один. Честно говоря, я удивлен, что этой функции еще нет в базовой Java.

g00se 08.07.2024 12:42

«еще нет в базовой Java» -- StandardCharsets.UTF_16 и StandardCharsets.UTF_32 должны отфильтровывать спецификации (UTF-8 вообще не должен использовать спецификацию, но встречается в некоторых приложениях Windows/Microsoft)

user85421 08.07.2024 14:58
new String(new byte[]{(byte)-2,(byte)-1,0,79,0,75}, "UTF-16") --> "OK" (нет НЕРАЗРЫВНОГО ПРОСТРАНСТВА НУЛЕВОЙ ШИРИНЫ в первой позиции)
user85421 08.07.2024 15:05

... должен отфильтровывать спецификации... Странно, я так думал, но это не так (по крайней мере здесь): String s = Files.readString(Path.of("people.utf_16be.csv"), StandardCharsets.UTF_16BE);s.codePointAt(0);$16 ==> 65279 (Jshell) (Файл со спецификацией)

g00se 08.07.2024 16:33

@user85421 user85421 Я только что понял, что разместил свой первый комментарий не в том месте. Это должно быть ЗДЕСЬ Также ваш комментарий здесь неверен, так как все методы чтения должны оставаться неделегированными (iow должны быть переопределены), иначе они не будут фильтроваться.

g00se 08.07.2024 18:05

ну, есть разница между UTF_16 и UTF_16BE (или UTF_16LE) - более поздние НЕ подавляют BOM (нет необходимости в BOM?) - из ссылки, которую я разместил выше: "При декодировании UTF-16BE, UTF-16LE, Кодировки UTF-32BE и UTF-32LE интерпретируют начальные метки порядка байтов как НЕРАЗРЫВАЮЩЕЕ ПРОСТРАНСТВО НУЛЕВОЙ ШИРИНЫ... При декодировании кодировки UTF-16 и UTF-32 интерпретируют метку порядка байтов в начале входной поток для указания порядка байтов..."

user85421 08.07.2024 19:20

@user85421 user85421, боюсь, я тоже вас запутал;) Сейчас мы оба публикуем комментарии о чтении спецификации в вопросе, который не имеет абсолютно никакого отношения к спецификациям. Это обсуждение имеет ценность, но комментарии следует переместить сюда

g00se 08.07.2024 20:26

Другие вопросы по теме