У меня есть 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)
.
Как насчет того, чтобы попробовать функцию замены регулярного выражения?
@user85421 на высоте
Да, @Sören, правильно, для меня проблема не в том, как внести изменения в String, а в том, как не использовать String в этом процессе.
Попробуйте это. Отказ от ответственности: проверено только поверхностно. Комментарии показывают, насколько легко это использовать повторно.
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 - верно, да
Лучший способ справиться с этим — использовать FilterReader
, который отфильтровывает спецификации. Они существуют. iirc, в Commons IO может быть один. Честно говоря, я удивлен, что этой функции еще нет в базовой Java.
«еще нет в базовой Java» -- StandardCharsets.UTF_16 и StandardCharsets.UTF_32 должны отфильтровывать спецификации (UTF-8 вообще не должен использовать спецификацию, но встречается в некоторых приложениях Windows/Microsoft)
new String(new byte[]{(byte)-2,(byte)-1,0,79,0,75}, "UTF-16")
--> "OK"
(нет НЕРАЗРЫВНОГО ПРОСТРАНСТВА НУЛЕВОЙ ШИРИНЫ в первой позиции)
... должен отфильтровывать спецификации... Странно, я так думал, но это не так (по крайней мере здесь): String s = Files.readString(Path.of("people.utf_16be.csv"), StandardCharsets.UTF_16BE);s.codePointAt(0);$16 ==> 65279
(Jshell) (Файл со спецификацией)
@user85421 user85421 Я только что понял, что разместил свой первый комментарий не в том месте. Это должно быть ЗДЕСЬ Также ваш комментарий здесь неверен, так как все методы чтения должны оставаться неделегированными (iow должны быть переопределены), иначе они не будут фильтроваться.
ну, есть разница между UTF_16
и UTF_16BE
(или UTF_16LE
) - более поздние НЕ подавляют BOM (нет необходимости в BOM?) - из ссылки, которую я разместил выше: "При декодировании UTF-16BE, UTF-16LE, Кодировки UTF-32BE и UTF-32LE интерпретируют начальные метки порядка байтов как НЕРАЗРЫВАЮЩЕЕ ПРОСТРАНСТВО НУЛЕВОЙ ШИРИНЫ... При декодировании кодировки UTF-16 и UTF-32 интерпретируют метку порядка байтов в начале входной поток для указания порядка байтов..."
@user85421 user85421, боюсь, я тоже вас запутал;) Сейчас мы оба публикуем комментарии о чтении спецификации в вопросе, который не имеет абсолютно никакого отношения к спецификациям. Это обсуждение имеет ценность, но комментарии следует переместить сюда
возможно, вариант использования FilterReader