3

the incoming pattern and format, given they are both lower cased, how can I change the below snippet of code so that the startsWith and endsWith return true if the pattern and format are matched case insensitive?

  try (Stream<Path> paths = Files.find(cobDir, 1,
            (path, attrs) -> attrs.isRegularFile()
                    && path.getFileName().startsWith(pattern)
                    && path.toString().endsWith(format))) {
        matchingFile = paths.findFirst();
    } catch (IOException e) {
        logger.error("Problem with getting files to process {}", e.getMessage());
    }

Is there a prettier way of doing this than the below:

    try (Stream<Path> paths = Files.find(cobDir, 1,
            (path, attrs) -> attrs.isRegularFile()
                    && path.getFileName().toString().toLowerCase().startsWith(pattern)
                    && path.toString().toLowerCase().endsWith(format))) {
        matchingFile = paths.findFirst();
    } catch (IOException e) {
        logger.error("Problem with getting files to process {}", e.getMessage());
    }
M06H
  • 1,675
  • 3
  • 36
  • 76

4 Answers4

3

startsWith and endsWith are just special cases of matching a string region and can be handled by the general regionMatches method as well:

  • string.startsWith(pattern) can be replaced by
    string.regionMatches(true, 0, pattern, 0, pattern.length())
  • string.endsWith(format) can be replaced by
    string.regionMatches(true, string.length()-format.length(), format, 0, format.length())

The first parameter argument (true) indicates that a case insensitive matching is desired.

In the second case, the string has to be stored into a local variable first, to be able to invoke two methods on it, which might be less convenient, however, this is still preferable over converting the string to upper case or lower case and invoking startsWith or endsWith:

First of all, converting to either, upper case or lower case, is not sufficient to handle all characters for a case insensitive matching. As the documentation of regionMatches mentiones, both have to be checked, due to irregular case mappings of certain Unicode characters. Granted, this might be unnecessary, when you are sure to only process ASCII or Latin strings.

On the other hand, converting the entire string when you only want to match a region at the beginning or end, is doing much more than necessary. Especially for cases where the string sizes preclude a match in the first place. regionMatches checks this first. It also doesn’t perform case conversions if the characters already match without.

So regionMatches handles irregular case mappings and is more efficient.

Holger
  • 285,553
  • 42
  • 434
  • 765
1

Solution 1: Don't test for uppercase and lowercase, just change the input/test value to be lowercase & just check for lowercase:-

try (Stream<Path> paths = Files.find(cobDir, 1,
            (path, attrs) -> attrs.isRegularFile()
                    && path.getFileName().toLowerCase().startsWith(pattern)
                    && path.toString().toLowerCase().endsWith(format))) {
        matchingFile = paths.findFirst();
    } catch (IOException e) {
        logger.error("Problem with getting files to process {}", e.getMessage());
    }

Solution 2: Change the regex expression (which you haven't included) to not take case into account:-

Is there a better way to format it, yes:-

try (Stream<Path> paths = getPaths()){
...
}

and stick all the ugly stuff in a function:-

private Stream<Path> getPaths(/** cobDir, pattern, format */){
  return Files.find(cobDir, 1,
              (path, attrs) -> attrs.isRegularFile()
                      &&
    path.getFileName().toString().toLowerCase().startsWith(pattern)
                      && path.toString().toLowerCase().endsWith(format))
}
Ross Drew
  • 8,163
  • 2
  • 41
  • 53
1

Use String class toLowerCase() method. e.g.,

Path p = new File("res.txt").toPath();

p.toString.toLowerCase() ...... endsWith() or startsWith(), you can use the methods for a string argument as both methods endsWith and startsWith are overloaded with 2 variants
1) as Path class argument
2) as String argument.

sorak
  • 2,607
  • 2
  • 16
  • 24
Mithun Theertha
  • 131
  • 2
  • 6
0

I would use a case-insensitive regular expression for this.

final Pattern FILTER = Pattern.compile(
    Pattern.quote(pattern) + ".*" + Pattern.quote(format),
    Pattern.CASE_INSENSITIVE
);
Optional<Path> matchingFile = Files.find(cobDir, 1, (path, attrs) ->
        attrs.isRegularFile() && FILTER.matcher(path.toString()).matches()
    )
    .findFirst();
Matthias Ronge
  • 9,403
  • 7
  • 47
  • 63