5

I'm trying to make a scrabble helper in bash, which when given a list of characters, finds all the words in the /usr/share/dict/words file.
For example, when given the letters a,c,r,t
The word cart will match
The word car will also match
The word carat will not match

However, if a,a,c,r,t were given
Then carat would have matched.

I am trying to find if it is possible only using grep, I suspect that brace expansions like
{a,c,r,t}{a,c,r,t} might be useful to generate all the possible combinations of the letters but instead I am greeted with the errors like

grep: aaac: No such file or directory
grep: aaar: No such file or directory
grep: aaat: No such file or directory   

when running the command
$ grep {a,c,r,t}{a,c,r,t}{a,c,r,t}{a,c,r,t} /usr/share/dict/words

When I use quotes like "{a,c,r,t}{a,c,r,t}" or "\{a,c,r,t\}\{a,c,r,t\}", brace expansion does not work at all

I know that the above command should not work as a scrabble helper but the errors are still rather unexpected. What is wrong with the command and how do I fix it? Also, can grep be used some way to make a scrabble helper at all?

  • Maybe awk with a length requirement and pattern matches for each letter? – Jeff Schaller Dec 21 '15 at 12:46
4

Regular expressions are not the best tool for this kind of job. I'd do something like:

perl -CLASD -lne '
  BEGIN{$l0{$_}++ for (split "", shift)}
  %l = %l0; for (split "") {next LINE unless $l{$_}--}
  print' aacrt < /usr/share/dict/words

Or since (at least in French and English and some other languages using the latin alphabet), scrabble only has the 26 uppercase letters A to Z (été is written as ETE, cœur as COEUR), with GNU iconv:

iconv -t us//TRANSLIT < /usr/share/dict/words |
  perl -CLASD -lne '
    BEGIN{$l0{$_}++ for (split "", uc shift)}
    %l = %l0; for (split "", uc $_) {next LINE unless $l{$_}--}
    print' croeu

Or to output in the original form:

perl -CLASD -MText::Unidecode -lne '
  BEGIN{$l0{$_}++ for (split "", uc shift)}
  %l = %l0; for (split "", uc unidecode $_) {next LINE unless $l{$_}--}
  print' croeu < /usr/share/dict/word
2

What is happening here is that the {a,c,r,t}{a,c,r,t}{a,c,r,t}{a,c,r,t} is expanded by shell you are using. That means the first of those (aaaa) is the pattern that grep will search on aaac, aaar, etc., as if you typed:

grep aaaa aaac aaar aaat aaca ..... /usr/share/dict/words

Put the search pattern in single quotes to prevent this from happening:

grep '{a,c,r,t}{a,c,r,t}{a,c,r,t}{a,c,r,t}' /usr/share/dict/words

On the on the other hand, I am not sure if you using the right syntax for grep here. I would use:

grep '[acrt][acrt][acrt][actr]' /usr/share/dict/words

which matches those combinations of 4 characters, and as @mueh commented:

grep -xE '[acrt]{1,4}' /usr/share/dict/words

to match 1-4 combinations of those letters.

  • I tried double quotes with and without escaping which didn't work. I just tried your single quotes suggestion which also doesn't return any result strangely. I would expect words like cart or scratch or carts or cartoon to pop up... – AvZ Dec 21 '15 at 8:48
  • @AvZ Didn't look at the actual output. I updated the answer with a form that will give results ([] specifying a set of characters to match in regex matching) – Anthon Dec 21 '15 at 8:54
  • 2
    I'd suggest '^[acrt]{1,4}$' as the OP wants to match "car" for example too. – meuh Dec 21 '15 at 8:54
  • Very strange, I understand how '^[acrt]{1,4}$' should be sufficient but it doesn't return any result! – AvZ Dec 21 '15 at 9:02
  • 1
    @AvZ '^[acrt]{1,4}$' is extended regexp, for that you need to specify grep -E '^[acrt]{1,4}$' /usr/share/dict/words. Not sure how you can prevent the repetition. – Anthon Dec 21 '15 at 9:34

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.