简体   繁体   中英

Check that string contains a character from array

I would like to check that string that is a filename contains a illegal argument from the ILLEGAL_CHARACTERS . Simply I could use for loop, but I want to do this by Streams .

My code:

package shared;

import java.util.Arrays;

public class Validator {
    private static final Character[] ILLEGAL_CHARACTERS =
            {'/','\n','\r','\t','\0','\f','`','?','*','\\','<','>','|','\"',':'};

    public static boolean fileNameIsValid(String fileName) {
        return Arrays.stream(ILLEGAL_CHARACTERS).anyMatch(fileName::contains);
    }
}

Problem is in contains method cuz It needs a CharSequence instead of char . Is there any way to do this by stream without changing Character[] type to String[] ?

Streams might not the best fit here. Also, now your solution has quadratic complexity (N*M, where N is the file name length, and M is the size of your illegal character array), which is not very performant. As proposed in the comments, you could use a regular expression:

private static final Pattern ILLEGAL_CHARACTERS_REGEX =
        Pattern.compile("[/\n\r\t\0\f`?*\\\\<>|\":]");

public static boolean fileNameIsValidRegex(String fileName) {
    return !ILLEGAL_CHARACTERS_REGEX.matcher(fileName).find();
}

Or, if your illegal character set is limited to ASCII, you could play around with a bitset to squeeze some performance:

private static final BitSet ILLEGAL_CHARACTERS = new BitSet();

static {
    for (char c : new char[]{
            '/','\n','\r','\t','\0','\f','`','?','*','\\','<','>','|','\"',':'}) {
        ILLEGAL_CHARACTERS.set(c);
    }
}

public static boolean fileNameIsValid(String fileName) {
    return fileName.chars().noneMatch(ILLEGAL_CHARACTERS::get);
}

You can try to use indexOf :

return Arrays.stream(ILLEGAL_CHARACTERS)
             .map(fileName::indexOf)
             .anyMatch(i -> i >= 0);

First, I would recommend that you use a Set instead of an array, because you don't have any need for indexing your stuff, then Stream over the characters from the given string, and check if there is any match with your set.

Get the chars from the chars() method on a string, this will give you a array of integeres, which you then can cast to an char "array"

Here's all you need:

private static final Set<Character> ILLEGAL_CHARACTERS = Set.of(
        '/','\n','\r','\t','\0','\f','`','?','*','\\','<','>','|','\"',':');

public static boolean fileNameIsValid(String fileName) {
    return fileName.chars()
            .mapToObj(c -> (char) c)
            .noneMatch(ILLEGAL_CHARACTERS::contains);
}

If contains method needs a CharSequence instead of char , then you can give it to it :

Arrays.stream(ILLEGAL_CHARACTERS)
        .map(String::valueOf)
        .anyMatch(fileName::contains);

But under the hood in the String class, this method uses indexOf(String str) method:

public boolean contains(CharSequence s) {
    return indexOf(s.toString()) > -1;
}

So, to avoid redundant type conversion, you can use another indexOf(int ch) method:

Arrays.stream(ILLEGAL_CHARACTERS).anyMatch(ch -> fileName.indexOf(ch) > -1);

See also: How to “subtract” 2 given strings In Java?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM