3

Elixir provides Path.wildcard, which uses the Erlang :filelib.wildcard function internally.

Matching is case-sensitive, for example, "a" does not match "A". (http://erlang.org/doc/man/filelib.html#wildcard-1)

Please is there a case-insensitive alternative?

Charles Okwuagwu
  • 10,538
  • 16
  • 87
  • 157
  • 1
    I don't think there's any way to do that with that function. If the root directory is not too large, you could fetch the whole list and filter using a case-insensitive regex. – Dogbert Aug 09 '17 at 17:37
  • would have been neat if we could use the [options] to specify :case_insensitive – Charles Okwuagwu Aug 09 '17 at 17:39
  • Actually you could do a simple string transform, replacing all letters with both its lower and uppercase version in square brackets, e.g. `abc` -> `[aA][bB][cC]`. I'll post an answer in a few minutes. – Dogbert Aug 09 '17 at 17:40
  • BTW, what’s particularily wrong with [`System.cmd/3`](https://hexdocs.pm/elixir/System.html#cmd/3): `System.cmd("find", ["." "-iname", "readme")`? – Aleksei Matiushkin Aug 10 '17 at 05:56

1 Answers1

4

There's no built in option to do this, but since the wildcard syntax supports character alternations similar to regex, you can replace every letter with an alternation of its lower and upper case versions, e.g. f0o -> [fF]0[oO], and then pass that to Path.wildcard/1. Here's a simple implementation that does this for ASCII letters:

defmodule A do
  def case_insensitive_glob(glob) do
    Regex.replace(~r/[a-zA-Z]/, glob, fn letter ->
      "[#{String.downcase(letter)}#{String.upcase(letter)}]"
    end)
  end
end

glob = A.case_insensitive_glob("**/*reAdmE.*") |> IO.inspect
Path.wildcard(glob) |> IO.inspect

Running this in the OTP source code produces all files with their name containing "reAdmE." in any case.

"**/*[rR][eE][aA][dD][mM][eE].*"
["README.md", "erts/emulator/pcre/README.pcre_update.md",
 "lib/erl_interface/src/README.internal",
 "lib/ic/examples/pre_post_condition/ReadMe.txt", "xcomp/README.md"]

I've verified the output's correctness with find:

$ find . -iname 'readme.*'
./erts/emulator/pcre/README.pcre_update.md
./lib/erl_interface/src/README.internal
./lib/ic/examples/pre_post_condition/ReadMe.txt
./README.md
./xcomp/README.md
Dogbert
  • 212,659
  • 41
  • 396
  • 397
  • I believe we could escape the entire path with this case-insensitive function and apply it to Elixir's Path.wildcard, if a :case_insensitive option is chosen. Would this be expensive? – Charles Okwuagwu Aug 09 '17 at 17:55
  • 4
    If Elixir ever adds this functionality, they'll probably want to support Unicode letters as well and also replace the `Regex.replace` with a hand rolled alternative that uses recursion + pattern matching to do the replace, for performance. – Dogbert Aug 09 '17 at 18:06