GNU coreutils, 56 bytes but broken plus awk, 117 bytes but broken132 bytes
Use grep 37 times to pull out the first word for each letter. (56 bytes)The script:
grep -o '[A-Za-z0-9_]*'>F
echo r=^\($(for l in {a..z} {0..9} _;do grep -im1 ^$l F;doneF;done|tr \\n \|)~\)$
echo $(egrep "$r" F|awk '!x[$0]++')
Explanation:
-o
matches legal words and prints each on its own line.grep -o
matches the legal words, printing each on its own line, which we save to a file F
.
-i
is case-insensitive. Then we loop the 37 potential starting "letters".
-m1
prints just the first match. For each letter we do a case insensitive search with -i
,
echo ...
is a naughty way to turn the lines back into space-delimited words. and use -m1
to print only the first match (or nothing).
We combine the results into a regular expression called r
, for example:
r=^(are|dogs|Look|There|3|_|~)$
egrep
uses that regexp to pull out only the desired words.
But if any of the desired words appear more than once, egrep
will display all of them. So we use awk
to remove the duplicates.
Finally echo $(...)
turns the lines back into space-delimited words. (This technique is not recommended for general use, since echo -n
does not print -n
!)
But this does not preserve the original order of words in the input. That requirement wasn't explicitly stated in the question, butUsing it was heavily implied by the sample outputs.:
$ echo "Look ^_^ .... There are 3 little dogs :)" | bash ./test.sh
are dogs Look _ There are 3 _dogs
So in order to restore the original word order, we need one more grep, this time selecting all (any) of the desired words. (117 bytes)
grep -o '[A-Za-z0-9_]*'>F
r=^\($(for l in {a..z} {0..9} _;do grep -im1 ^$l F;done|tr \\n \|)~\)$
egrep "$r" F|trecho \\n"Take \all
By way of explanation, this is the regexp you see if you echo "$r"
:
^(are|dogs|Look|There|3|_|~)$
Example use:
$first echowords "Lookfor ^_^each .letter... There are 3this littleis dogsa :)"test" | bash ./test.sh
LookTake _all Therefirst arewords 3each dogsletter is
Unfortunately that final grep will happily match a duplicated word more than once!
$ echo 'Oh no multiple no noooooo no argh!' | bash ./test.sh
Oh no multiple no no argh
So at this point I will admit defeat, throw up my hands, and just share what I have so far.
I had originallyinitially hoped to get a nice simple solution usinguse uniqsort|uniq -w1iw1
, but removing duplicates requires sorting:
tr \ \\n|sort|uniq -iw1|tr \\n \
And sort
sort would always place "a" before "and":
$ echo "Take all first words for each letter... this is a test" | bash ./test.sh
a each first is letter... Take words
I would love to hear from you if you know how to get sort
to sort lines by the first character only, and otherwise preserve order. (I failed"all". Since I had to master sort
'suse -kawk
option.)
But even in that case, restoring the original order of the words appears to be difficult.
If only uniq
could work on unsorted inputend, weI could have gotten away with it. And my answer would have been muchjust gone for a shorter too. ;-)solution with awk
alone!