Java Programmer
Java Programmer

Reputation: 1413

Java 8 filtering a string

I have a method to remove some characters from a string. Is there a better way to do this using java 8?

public String filter(String test) {
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < test.length(); i++) {
        if (MYCOLLECTION.contains(test.charAt(i))) {
            builder .append(test.charAt(i));
        }
    }
    return builder .toString();
}

Upvotes: 9

Views: 13476

Answers (4)

Luc-Olivier
Luc-Olivier

Reputation: 3973

Here is a very simple way using Regex

var string = "what ever you want!";

final var charSet = "".,;:!@";

final var stringResult = string.replaceAll("[" + charSet + "]", "");

>> ""what ever you want"

Upvotes: 0

Donald Raab
Donald Raab

Reputation: 6686

If you're open to using a third-party library, the following will work using Java 8 with Eclipse Collections.

CharSet set = CharSets.immutable.with('a', 'b', 'c');
CharAdapter chars = Strings.asChars("a1b2c3");
String string = chars.select(set::contains).toString();
Assert.assertEquals("abc", string);

Eclipse Collections has support for primitive collections so there is no need to box char values as Character instances.

You can also exclude instead of include characters using the method named reject which is the opposite of select.

CharSet set = CharSets.immutable.with('a', 'b', 'c');
CharAdapter chars = Strings.asChars("a1b2c3");
String include = chars.select(set::contains).toString();
String exclude = chars.reject(set::contains).toString();
Assert.assertEquals("abc", include);
Assert.assertEquals("123", exclude);

Note: I am a committer for Eclipse Collections.

Upvotes: 1

Michael
Michael

Reputation: 44150

"Better" by what metric? Here's how I would write it

final String filtered = test.chars()
    .mapToObj(chr -> (char) chr)    // IntStream -> Stream<Character>
    .filter(MYCOLLECTION::contains)
    .collect(
        Collector.of(StringBuilder::new, StringBuilder::append, StringBuilder::append, StringBuilder::toString)
    );

The collector is a bit ugly, I would probably extract it to its own method

private static Collector<Character, StringBuilder, String> characterCollector()
{
    return Collector.of(
        StringBuilder::new,
        StringBuilder::append,
        StringBuilder::append,
        StringBuilder::toString
    );
}

Then call this instead

.collect(characterCollector())

Upvotes: 1

Eran
Eran

Reputation: 393811

How about this:

Set<Character> filter = new HashSet<>(Arrays.asList('a','b','c'));
String filtered = "abcdefga".chars ()
                            .filter(i -> filter.contains((char) i))
                            .mapToObj(i -> "" + (char) i)
                            .collect(Collectors.joining());
System.out.println (filtered);

Output:

abca

Note: filter serves the same purpose as your MYCOLLECTION - I just gave it a more meaningful name and used a Set for better performance of contains.

It could have been cleaner if there was a CharStream (i.e. stream of primitive chars), so I wouldn't have to use an IntStream.

Upvotes: 5

Related Questions