Skip to content

Commit 8a681ea

Browse files
author
Gary Gregory
committed
Variation of PR #227 from Rob Spoor (robtimus) but does not add a new
class. - Add AbstractCharacterFilterReader(Reader, IntPredicate). - Add CharacterFilterReader(Reader, IntPredicate). - Add AbstractCharacterFilterReader(Reader, IntPredicate). - Add CharacterFilterReaderIntPredicateTest.
1 parent 4b7cc53 commit 8a681ea

4 files changed

Lines changed: 168 additions & 26 deletions

File tree

src/main/java/org/apache/commons/io/input/AbstractCharacterFilterReader.java

Lines changed: 27 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,19 +21,46 @@
2121
import java.io.FilterReader;
2222
import java.io.IOException;
2323
import java.io.Reader;
24+
import java.util.function.IntPredicate;
2425

2526
/**
2627
* A filter reader that filters out characters where subclasses decide which characters to filter out.
2728
*/
2829
public abstract class AbstractCharacterFilterReader extends FilterReader {
2930

31+
private static final IntPredicate SKIP_NONE = ch -> false;
32+
33+
private final IntPredicate skip;
34+
3035
/**
3136
* Constructs a new reader.
3237
*
3338
* @param reader the reader to filter
3439
*/
3540
protected AbstractCharacterFilterReader(final Reader reader) {
41+
this(reader, SKIP_NONE);
42+
}
43+
44+
/**
45+
* Constructs a new reader.
46+
*
47+
* @param reader the reader to filter.
48+
* @param skip Skip test.
49+
* @since 2.9.0
50+
*/
51+
protected AbstractCharacterFilterReader(final Reader reader, final IntPredicate skip) {
3652
super(reader);
53+
this.skip = skip == null ? SKIP_NONE : skip;
54+
}
55+
56+
/**
57+
* Returns true if the given character should be filtered out, false to keep the character.
58+
*
59+
* @param ch the character to test.
60+
* @return true if the given character should be filtered out, false to keep the character.
61+
*/
62+
protected boolean filter(final int ch) {
63+
return skip.test(ch);
3764
}
3865

3966
@Override
@@ -45,14 +72,6 @@ public int read() throws IOException {
4572
return ch;
4673
}
4774

48-
/**
49-
* Returns true if the given character should be filtered out, false to keep the character.
50-
*
51-
* @param ch the character to test.
52-
* @return true if the given character should be filtered out, false to keep the character.
53-
*/
54-
protected abstract boolean filter(int ch);
55-
5675
@Override
5776
public int read(final char[] cbuf, final int off, final int len) throws IOException {
5877
final int read = super.read(cbuf, off, len);

src/main/java/org/apache/commons/io/input/CharacterFilterReader.java

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
package org.apache.commons.io.input;
1818

1919
import java.io.Reader;
20+
import java.util.function.IntPredicate;
2021

2122
/**
2223
* A filter reader that filters out a given character represented as an {@code int} code point, handy to remove
@@ -25,8 +26,6 @@
2526
*/
2627
public class CharacterFilterReader extends AbstractCharacterFilterReader {
2728

28-
private final int skip;
29-
3029
/**
3130
* Constructs a new reader.
3231
*
@@ -36,13 +35,18 @@ public class CharacterFilterReader extends AbstractCharacterFilterReader {
3635
* the character to filter out.
3736
*/
3837
public CharacterFilterReader(final Reader reader, final int skip) {
39-
super(reader);
40-
this.skip = skip;
38+
super(reader, c -> c == skip);
4139
}
4240

43-
@Override
44-
protected boolean filter(final int ch) {
45-
return ch == skip;
41+
/**
42+
* Constructs a new reader.
43+
*
44+
* @param reader the reader to filter.
45+
* @param skip Skip test.
46+
* @since 2.9.0
47+
*/
48+
public CharacterFilterReader(final Reader reader, final IntPredicate skip) {
49+
super(reader, skip);
4650
}
4751

4852
}

src/main/java/org/apache/commons/io/input/CharacterSetFilterReader.java

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,6 @@
3232
*/
3333
public class CharacterSetFilterReader extends AbstractCharacterFilterReader {
3434

35-
private static final Set<Integer> EMPTY_SET = Collections.emptySet();
36-
private final Set<Integer> skipSet;
37-
3835
/**
3936
* Constructs a new reader.
4037
*
@@ -53,14 +50,7 @@ public CharacterSetFilterReader(final Reader reader, final Integer... skip) {
5350
* @param skip the set of characters to filter out.
5451
*/
5552
public CharacterSetFilterReader(final Reader reader, final Set<Integer> skip) {
56-
super(reader);
57-
this.skipSet = skip == null ? EMPTY_SET : Collections.unmodifiableSet(skip);
58-
}
59-
60-
@Override
61-
protected boolean filter(final int ch) {
62-
// Note WRT Integer.valueOf(): You can increase the Integer cache with a system property, see {@link Integer}.
63-
return skipSet.contains(Integer.valueOf(ch));
53+
super(reader, c -> skip == null ? null : Collections.unmodifiableSet(skip).contains(Integer.valueOf(c)));
6454
}
6555

6656
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one or more
3+
* contributor license agreements. See the NOTICE file distributed with
4+
* this work for additional information regarding copyright ownership.
5+
* The ASF licenses this file to You under the Apache License, Version 2.0
6+
* (the "License"); you may not use this file except in compliance with
7+
* the License. You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
package org.apache.commons.io.input;
18+
19+
import static org.junit.jupiter.api.Assertions.assertEquals;
20+
21+
import java.io.IOException;
22+
import java.io.StringReader;
23+
import java.util.function.IntPredicate;
24+
25+
import org.apache.commons.io.IOUtils;
26+
import org.apache.commons.io.output.StringBuilderWriter;
27+
import org.apache.commons.lang3.StringUtils;
28+
import org.junit.jupiter.api.Test;
29+
30+
/**
31+
* Tests {@link CharacterFilterReader} with an {@link IntPredicate}.
32+
*/
33+
public class CharacterFilterReaderIntPredicateTest {
34+
35+
@Test
36+
public void testInputSize0FilterAll() throws IOException {
37+
final StringReader input = new StringReader(StringUtils.EMPTY);
38+
try (CharacterFilterReader reader = new CharacterFilterReader(input, ch -> true)) {
39+
assertEquals(-1, reader.read());
40+
}
41+
}
42+
43+
@Test
44+
public void testInputSize1FilterAll() throws IOException {
45+
try (StringReader input = new StringReader("a");
46+
CharacterFilterReader reader = new CharacterFilterReader(input, ch -> true)) {
47+
assertEquals(-1, reader.read());
48+
}
49+
}
50+
51+
@Test
52+
public void testInputSize2FilterAll() throws IOException {
53+
final StringReader input = new StringReader("aa");
54+
try (CharacterFilterReader reader = new CharacterFilterReader(input, ch -> true)) {
55+
assertEquals(-1, reader.read());
56+
}
57+
}
58+
59+
@Test
60+
public void testInputSize2FilterFirst() throws IOException {
61+
final StringReader input = new StringReader("ab");
62+
try (CharacterFilterReader reader = new CharacterFilterReader(input, ch -> ch == 'a')) {
63+
assertEquals('b', reader.read());
64+
assertEquals(-1, reader.read());
65+
}
66+
}
67+
68+
@Test
69+
public void testInputSize2FilterLast() throws IOException {
70+
final StringReader input = new StringReader("ab");
71+
try (CharacterFilterReader reader = new CharacterFilterReader(input, ch -> ch == 'b')) {
72+
assertEquals('a', reader.read());
73+
assertEquals(-1, reader.read());
74+
}
75+
}
76+
77+
@Test
78+
public void testInputSize5FilterWhitespace() throws IOException {
79+
final StringReader input = new StringReader(" a b ");
80+
try (CharacterFilterReader reader = new CharacterFilterReader(input, Character::isWhitespace)) {
81+
assertEquals('a', reader.read());
82+
assertEquals('b', reader.read());
83+
assertEquals(-1, reader.read());
84+
}
85+
}
86+
87+
@Test
88+
public void testReadIntoBuffer() throws IOException {
89+
final StringReader input = new StringReader("ababcabcd");
90+
try (CharacterFilterReader reader = new CharacterFilterReader(input, ch -> ch == 'b')) {
91+
final char[] buff = new char[9];
92+
final int charCount = reader.read(buff);
93+
assertEquals(6, charCount);
94+
assertEquals("aacacd", new String(buff, 0, charCount));
95+
}
96+
}
97+
98+
@Test
99+
public void testReadIntoBufferFilterWhitespace() throws IOException {
100+
final StringReader input = new StringReader(" a b a b c a b c d ");
101+
try (CharacterFilterReader reader = new CharacterFilterReader(input, Character::isWhitespace)) {
102+
final char[] buff = new char[19];
103+
final int charCount = reader.read(buff);
104+
assertEquals(9, charCount);
105+
assertEquals("ababcabcd", new String(buff, 0, charCount));
106+
}
107+
}
108+
109+
@Test
110+
public void testReadUsingReader() throws IOException {
111+
final StringReader input = new StringReader("ababcabcd");
112+
try (StringBuilderWriter output = new StringBuilderWriter();
113+
CharacterFilterReader reader = new CharacterFilterReader(input, ch -> ch == 'b')) {
114+
IOUtils.copy(reader, output);
115+
assertEquals("aacacd", output.toString());
116+
}
117+
}
118+
119+
@Test
120+
public void testReadUsingReaderFilterWhitespace() throws IOException {
121+
final StringReader input = new StringReader(" a b a b c a b c d ");
122+
try (StringBuilderWriter output = new StringBuilderWriter();
123+
CharacterFilterReader reader = new CharacterFilterReader(input, Character::isWhitespace)) {
124+
IOUtils.copy(reader, output);
125+
assertEquals("ababcabcd", output.toString());
126+
}
127+
}
128+
129+
}

0 commit comments

Comments
 (0)