ABC words

From Rosetta Code
Task
ABC words
You are encouraged to solve this task according to the task description, using any language you may know.


Definition

A word is an   ABC word   if the letters  "a",  "b"  and  "c"  appear in the word in alphabetical order.

If any or all of these letters occur more than once in a word, then only the first occurrence of each letter should be used to determine whether a word is an  ABC word  or not.


Task

Show here   (on this page)   every  ABC word  in unixdict.txt.


Other tasks related to string operations:
Metrics
Counting
Remove/replace
Anagrams/Derangements/shuffling
Find/Search/Determine
Formatting
Song lyrics/poems/Mad Libs/phrases
Tokenize
Sequences



11l

L(ln) File(‘unixdict.txt’).read().split("\n")
   V? a = ln.find(‘a’)
   I a != N
      V b = ln.findi(‘b’)
      I a < b & b < ln.findi(‘c’)
         print(ln)
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Action!

In the following solution the input file unixdict.txt is loaded from H6 drive. Altirra emulator automatically converts CR/LF character from ASCII into 155 character in ATASCII charset used by Atari 8-bit computer when one from H6-H10 hard drive under DOS 2.5 is used.

BYTE FUNC FindC(CHAR ARRAY text CHAR c)
  BYTE i

  i=1
  WHILE i<=text(0)
  DO
    IF text(i)=c THEN
      RETURN (i)
    FI
    i==+1
  OD
RETURN (0)

BYTE FUNC IsAbcWord(CHAR ARRAY word)
  BYTE a,b,c

  a=FindC(word,'a)
  IF a=0 THEN RETURN (0) FI
  b=FindC(word,'b)
  IF b<a THEN RETURN (0) FI
  c=FindC(word,'c)
  IF c<b THEN RETURN (0) FI
RETURN (1)

PROC FindAbcWords(CHAR ARRAY fname)
  CHAR ARRAY line(256)
  CHAR ARRAY tmp(256)
  BYTE pos,dev=[1]

  pos=2
  Close(dev)
  Open(dev,fname,4)
  WHILE Eof(dev)=0
  DO
    InputSD(dev,line)
    IF IsAbcWord(line) THEN
      IF pos+line(0)>=40 THEN
        PutE() pos=2
      FI
      Print(line) Put(32)
      pos==+line(0)+1
    FI
  OD
  Close(dev)
RETURN

PROC Main()
  CHAR ARRAY fname="H6:UNIXDICT.TXT"

  FindAbcWords(fname)
RETURN
Output:

Screenshot from Atari 8-bit computer

aback abacus abc abdicate abduct
abeyance abject abreact abscess
abscissa abscissae absence abstract
abstracter abstractor adiabatic
aerobacter aerobic albacore alberich
albrecht algebraic alphabetic
ambiance ambuscade aminobenzoic
anaerobic arabic athabascan auerbach
diabetic diabolic drawback fabric
fabricate flashback halfback iambic
lampblack leatherback metabolic
nabisco paperback parabolic playback
prefabricate quarterback razorback
roadblock sabbatical snapback
strabismic syllabic tabernacle
tablecloth

Ada

with Ada.Text_Io;
with Ada.Strings.Fixed;

procedure Abc_Words is
   use Ada.Text_Io;

   function Is_Abc_Word (Word : String) return Boolean is
      use Ada.Strings.Fixed;
      Pos_A : constant Natural := Index (Word, "a");
      Pos_B : constant Natural := Index (Word, "b");
      Pos_C : constant Natural := Index (Word, "c");
   begin
      return
        Pos_B > Pos_A and Pos_C > Pos_B and
        Pos_A /= 0 and Pos_B /= 0 and Pos_C /= 0;
   end Is_Abc_Word;

   Filename : constant String := "unixdict.txt";
   File     : File_Type;
   Column   : Ada.Text_Io.Count := 0;
begin
   Open (File, In_File, Filename);
   while not End_Of_File (File) loop
      declare
         Word : constant String := Get_Line (File);
      begin
         if Is_Abc_Word (Word) then
            Set_Col (1 + Column);
            Column := (Column + 15) mod 120;
            Put (Word);
         end if;
      end;
   end loop;
   Close (File);
end Abc_Words;
Output:
aback          abacus         abc            abdicate       abduct         abeyance       abject         abreact
abscess        abscissa       abscissae      absence        abstract       abstracter     abstractor     adiabatic
aerobacter     aerobic        albacore       alberich       albrecht       algebraic      alphabetic     ambiance
ambuscade      aminobenzoic   anaerobic      arabic         athabascan     auerbach       diabetic       diabolic
drawback       fabric         fabricate      flashback      halfback       iambic         lampblack      leatherback
metabolic      nabisco        paperback      parabolic      playback       prefabricate   quarterback    razorback
roadblock      sabbatical     snapback       strabismic     syllabic       tabernacle     tablecloth

ALGOL 68

With regular expressions

For use with compilers/interpreters that support using regular expressions via grep in string procedure which is available in ALGOL 68G.

Works with: ALGOL 68G version Any - tested with release 2.8.3.win32

Note, the source of files.incl.a68 is on a separate page on Rosetta Code - see the above link.

BEGIN # find words that have "a", "b" and "C" in order in them               #

    PR read "files.incl.a68" PR                     # include file utilities #

    # prints word if the characters "a", "b" and "c" appear in order in it   #
    # count so far is thw number of preceding "abc" words                    #
    # returns TRUE if word is such an "abc" word, FALSE otherwise            #
    PROC show abc word = ( STRING word, INT count so far )BOOL:
         IF   grep in string( "^[^bc]*a[^c]*b.*c", word, NIL, NIL ) = 0
         THEN INT abc count = count so far + 1;
              print( ( whole( abc count, -5 ), ": ", word, newline ) );
              TRUE
         ELSE FALSE
         FI # show abc word # ;

    IF "unixdict.txt" EACHLINE show abc word < 0 THEN
        print( ( "Unable to open unixdict.txt", newline ) )
    FI

END
Output:
    1: aback
    2: abacus
    3: abc
    4: abdicate
    5: abduct
    6: abeyance
    7: abject
    8: abreact
    9: abscess
   10: abscissa
   11: abscissae
   12: absence
   13: abstract
   14: abstracter
   15: abstractor
   16: adiabatic
   17: aerobacter
   18: aerobic
   19: albacore
   20: alberich
   21: albrecht
   22: algebraic
   23: alphabetic
   24: ambiance
   25: ambuscade
   26: aminobenzoic
   27: anaerobic
   28: arabic
   29: athabascan
   30: auerbach
   31: diabetic
   32: diabolic
   33: drawback
   34: fabric
   35: fabricate
   36: flashback
   37: halfback
   38: iambic
   39: lampblack
   40: leatherback
   41: metabolic
   42: nabisco
   43: paperback
   44: parabolic
   45: playback
   46: prefabricate
   47: quarterback
   48: razorback
   49: roadblock
   50: sabbatical
   51: snapback
   52: strabismic
   53: syllabic
   54: tabernacle
   55: tablecloth

Without regular expressions

An alternative version for compilers/interpreters that don't have the grep in string procedure

Note, the source of files.incl.a68 is on a separate page on Rosetta Code - see the above link.

BEGIN # find words that have "a", "b" and "C" in order in them               #

    PR read "files.incl.a68" PR                     # include file utilities #

    # prints word if the characters "a", "b" and "c" appear in order in it   #
    # count so far is thw number of preceding "abc" words                    #
    # returns TRUE if word is such an "abc" word, FALSE otherwise            #
    PROC show abc word = ( STRING word, INT count so far )BOOL:
         IF   INT w max  = UPB word;
              INT a pos := w max + 1;
              INT b pos := w max + 1;
              INT c pos := w max + 1;
              VOID( char in string( "a", a pos, word ) );
              VOID( char in string( "b", b pos, word ) );
              VOID( char in string( "c", c pos, word ) );
              a pos <  b pos
          AND b pos <  c pos
          AND c pos <= w max
         THEN INT abc count = count so far + 1;
              print( ( whole( abc count, -5 ), ": ", word, newline ) );
              TRUE
         ELSE FALSE
         FI # show abc word # ;

    IF "unixdict.txt" EACHLINE show abc word < 0 THEN
        print( ( "Unable to open unixdict.txt", newline ) )
    FI

END
Output:

Same as the regular expression version.

APL

Works with: Dyalog APL
abcwords{
    'abc'
    words((~∊)⎕TC⊆⊢) 80 ¯1⎕MAP 
    match/∊,2</
    (match¨words)/words
}
Output:
      11 5 ⍴ abcwords 'unixdict.txt'
 aback         abacus       abc         abdicate    abduct      
 abeyance      abject       abreact     abscess     abscissa    
 abscissae     absence      abstract    abstracter  abstractor  
 adiabatic     aerobacter   aerobic     albacore    alberich    
 albrecht      algebraic    alphabetic  ambiance    ambuscade   
 aminobenzoic  anaerobic    arabic      athabascan  auerbach    
 diabetic      diabolic     drawback    fabric      fabricate   
 flashback     halfback     iambic      lampblack   leatherback 
 metabolic     nabisco      paperback   parabolic   playback    
 prefabricate  quarterback  razorback   roadblock   sabbatical  
 snapback      strabismic   syllabic    tabernacle  tablecloth  

AppleScript

Core language

This is a fairly simple solution, hard-coded for "a", "b", and "c". The 'offset' commands are performed by AppleScript's StandardAdditions OSAX, so the time taken by the multiple communications between the script and the OSAX makes the code comparatively slow. Still, the overall running time with the specified file on my current machine is less than 1.5 seconds.

on abcWords(wordFile)
    -- The word file text is assumed to be UTF-8 encoded and to have one word per line.
    script o
        property wordList : paragraphs of (read wordFile as «class utf8»)
    end script
    
    set output to {}
    repeat with thisWord in o's wordList
        set thisWord to thisWord's contents
        if ((thisWord contains "c") and ¬
            (text 1 thru (offset of "c" in thisWord) of thisWord contains "b") and ¬
            (text 1 thru (offset of "b" in thisWord) of thisWord contains "a")) then ¬
            set end of output to thisWord
    end repeat
    
    return output
end abcWords

return abcWords(((path to desktop as text) & "www.rosettacode.org:unixdict.txt") as alias)
Output:
{"aback", "abacus", "abc", "abdicate", "abduct", "abeyance", "abject", "abreact", "abscess", "abscissa", "abscissae", "absence", "abstract", "abstracter", "abstractor", "adiabatic", "aerobacter", "aerobic", "albacore", "alberich", "albrecht", "algebraic", "alphabetic", "ambiance", "ambuscade", "aminobenzoic", "anaerobic", "arabic", "athabascan", "auerbach", "diabetic", "diabolic", "drawback", "fabric", "fabricate", "flashback", "halfback", "iambic", "lampblack", "leatherback", "metabolic", "nabisco", "paperback", "parabolic", "playback", "prefabricate", "quarterback", "razorback", "roadblock", "sabbatical", "snapback", "strabismic", "syllabic", "tabernacle", "tablecloth"}

The following alternative uses delimiters and text items instead and is considerably faster at around 0.25 seconds. Also, for the hell of it, it takes the characters (or even longer substrings) that the returned words must contain as a parameter. Same output here as above.

on abcWords(wordFile, theLetters)
    -- The word file text is assumed to be UTF-8 encoded and to have one word per line.
    script o
        property wordList : paragraphs of (read wordFile as «class utf8»)
    end script
    
    set output to {}
    set letterCount to (count theLetters)
    set astid to AppleScript's text item delimiters
    repeat with thisWord in o's wordList
        set thisWord to thisWord's contents
        set thisLetter to end of theLetters
        if (thisWord contains thisLetter) then
            set matched to true
            repeat with c from (letterCount - 1) to 1 by -1
                set AppleScript's text item delimiters to thisLetter
                set thisLetter to item c of theLetters
                set matched to (thisWord's first text item contains thisLetter)
                if (not matched) then exit repeat
            end repeat
            if (matched) then set end of output to thisWord
        end if
    end repeat
    set AppleScript's text item delimiters to astid
    
    return output
end abcWords

return abcWords(((path to desktop as text) & "www.rosettacode.org:unixdict.txt") as alias, {"a", "b", "c"})

AppleScriptObjC

This is faster still at 0.01 seconds and uses AppleScriptObjC to access the regex facilities provided by macOS's Foundation framework. It too takes the characters the returned words must contain as a parameter, but, unlike the script above, doesn't recognise longer substring inputs as units in themselves. Same output as with the two "Core language" scripts above.

use AppleScript version "2.4" -- OS X 10.10 (Yosemite) or later
use framework "Foundation"
use scripting additions

on abcWords(wordFile, theLetters)
    -- This NSString method used here guesses the word file's text encoding itself.
    set wordText to current application's class "NSString"'s stringWithContentsOfFile:(POSIX path of wordFile) ¬
        usedEncoding:(missing value) |error|:(missing value)
    
    -- Assuming one word per line, build a regex pattern to match words containing the specified letters in the given order.
    set theLetters to join(theLetters, "")
    set pattern to "(?mi)^"
    repeat with c from 1 to (count theLetters)
        set pattern to pattern & (("[^" & text c thru end of theLetters) & ("\\v]*+" & character c of theLetters))
    end repeat
    set pattern to pattern & ".*+$"
    
    set regexObj to current application's class "NSRegularExpression"'s ¬
        regularExpressionWithPattern:(pattern) options:(0) |error|:(missing value)
    
    set wordMatches to regexObj's matchesInString:(wordText) options:(0) range:({0, wordText's |length|()})
    set matchRanges to wordMatches's valueForKey:("range")
    
    set output to {}
    repeat with thisRange in matchRanges
        set end of output to (wordText's substringWithRange:(thisRange)) as text
    end repeat
    
    return output
end abcWords

on join(lst, delim)
    set astid to AppleScript's text item delimiters
    set AppleScript's text item delimiters to delim
    set txt to lst as text
    set AppleScript's text item delimiters to astid
    return txt
end join

return abcWords(((path to desktop as text) & "www.rosettacode.org:unixdict.txt") as alias, {"a", "b", "c"})

Arturo

words: read.lines relative "unixdict.txt"

isABC?: function [w][
    a: index w "a"
    if null? a -> return false
    b: index w "b"
    if null? b -> return false
    if b < a -> return false
    c: index w "c"
    if null? c -> return false
    if c < b -> return false
    return true 
]

loop words 'word [
    if isABC? word ->
        print word
]
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

AutoHotkey

FileRead, unixdict, unixdict.txt
Loop, Parse, unixdict, `n
	if ABCWord(A_LoopField)
	{
		count++
		text .= count ": " A_LoopField "`n"
	}
Msgbox, %text%

ABCWord(Word) {
	if InStr(Word, "a")
		if InStr(Word, "b") > InStr(Word, "a")
			if InStr(Word, "c") > InStr(Word, "b")
				return true
			else
				return false
		else
			return false
	else
		return false
}
Output:
1: aback
2: abacus
3: abc
4: abdicate
5: abduct
6: abeyance
7: abject
8: abreact
9: abscess
10: abscissa
11: abscissae
12: absence
13: abstract
14: abstracter
15: abstractor
16: adiabatic
17: aerobacter
18: aerobic
19: albacore
20: alberich
21: albrecht
22: algebraic
23: alphabetic
24: ambiance
25: ambuscade
26: aminobenzoic
27: anaerobic
28: arabic
29: athabascan
30: auerbach
31: diabetic
32: diabolic
33: drawback
34: fabric
35: fabricate
36: flashback
37: halfback
38: iambic
39: lampblack
40: leatherback
41: metabolic
42: nabisco
43: paperback
44: parabolic
45: playback
46: prefabricate
47: quarterback
48: razorback
49: roadblock
50: sabbatical
51: snapback
52: strabismic
53: syllabic
54: tabernacle
55: tablecloth

AWK

The following one-liner entered into a Posix shell returns the same 55 words as other entries.

awk  '/^[^bc]*a[^c]*b.*c/' unixdict.txt

BASIC

10 DEFINT A,B,C: DEFSTR W
20 OPEN "I",1,"unixdict.txt"
30 IF EOF(1) THEN END
40 LINE INPUT #1, W
50 A = INSTR(W,"a")
60 B = INSTR(W,"b")
70 C = INSTR(W,"c")
80 IF A>0 AND B>0 AND C>0 AND A<B AND B<C THEN PRINT W,
90 GOTO 30
Output:
aback         abacus        abc           abdicate      abduct
abeyance      abject        abreact       abscess       abscissa
abscissae     absence       abstract      abstracter    abstractor
adiabatic     aerobacter    aerobic       albacore      alberich
albrecht      algebraic     alphabetic    ambiance      ambuscade
aminobenzoic  anaerobic     arabic        athabascan    auerbach
diabetic      diabolic      drawback      fabric        fabricate
flashback     halfback      iambic        lampblack     leatherback
metabolic     nabisco       paperback     parabolic     playback
prefabricate  quarterback   razorback     roadblock     sabbatical
snapback      strabismic    syllabic      tabernacle    tablecloth

BCPL

get "libhdr"

let find(s, c) = valof
$(  for i=1 to s%0
        if s%i=c then resultis i
    resultis -1
$)

let match(word) = valof
$(  let a = find(word, 'a')
    let b = find(word, 'b')
    let c = find(word, 'c')
    resultis a ~= -1 & b ~= -1 & c ~= -1 & a<b & b<c
$)

let read(word) = valof
$(  let ch = ?
    word%0 := 0
    $(  ch := rdch()
        if ch = endstreamch then resultis false
        word%0 := word%0 + 1
        word%(word%0) := ch
    $) repeatuntil ch = '*N'
    resultis true
$)

let start() be
$(  let word = vec 63
    let file = findinput("unixdict.txt")
    test file = 0 then 
        writes("Cannot open unixdict.txt*N")
    else
    $(  selectinput(file)
        while read(word) if match(word) do writes(word)
        endread()
    $)
$)
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

BQN

Match  ⊣≡(˜∧∊)/⊢

•Show 5  "abc" <(Match¨/⊢) •Flines "unixdict.txt"
Output:
┌─
╵ "aback"        "abacus"      "abc"        "abdicate"   "abduct"
  "abeyance"     "abject"      "abreact"    "abscess"    "abscissa"
  "abscissae"    "absence"     "abstract"   "abstracter" "abstractor"
  "adiabatic"    "aerobacter"  "aerobic"    "albacore"   "alberich"
  "albrecht"     "algebraic"   "alphabetic" "ambiance"   "ambuscade"
  "aminobenzoic" "anaerobic"   "arabic"     "athabascan" "auerbach"
  "diabetic"     "diabolic"    "drawback"   "fabric"     "fabricate"
  "flashback"    "halfback"    "iambic"     "lampblack"  "leatherback"
  "metabolic"    "nabisco"     "paperback"  "parabolic"  "playback"
  "prefabricate" "quarterback" "razorback"  "roadblock"  "sabbatical"
  "snapback"     "strabismic"  "syllabic"   "tabernacle" "tablecloth"
                                                                       ┘

C

#include <stdio.h>
#include <string.h>

int match(const char *word) {
    const char *a = strchr(word, 'a');
    const char *b = strchr(word, 'b');
    const char *c = strchr(word, 'c');
    return a && b && c && a<b && b<c;
}

int main() {
    char word[80];
    FILE *file = fopen("unixdict.txt", "r");
    if (!file) {
        fprintf(stderr, "Cannot open unixdict.txt");
        return -1;
    }
    
    while (!feof(file)) {
        fgets(word, sizeof(word), file);
        if(match(word)) printf("%s", word);
    }
    return 0;
}
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

C#

Takes an optional command line for other character combinations. User can specify any reasonable number of unique characters. Caveat: see discussion page for issue about specifying repeated characters.

class Program {
    static void Main(string[] args) { int bi, i = 0; string chars = args.Length < 1 ? "abc" : args[0];
        foreach (var item in System.IO.File.ReadAllLines("unixdict.txt")) {
            int ai = -1; foreach (var ch in chars)
                if ((bi = item.IndexOf(ch)) > ai) ai = bi; else goto skip;
            System.Console.Write("{0,3} {1,-18} {2}", ++i, item, i % 5 == 0 ? "\n" : "");
        skip: ; } }
}
Output:

Without command line arguments:

  1 aback                2 abacus               3 abc                  4 abdicate             5 abduct
  6 abeyance             7 abject               8 abreact              9 abscess             10 abscissa
 11 abscissae           12 absence             13 abstract            14 abstracter          15 abstractor
 16 adiabatic           17 aerobacter          18 aerobic             19 albacore            20 alberich
 21 albrecht            22 algebraic           23 alphabetic          24 ambiance            25 ambuscade
 26 aminobenzoic        27 anaerobic           28 arabic              29 athabascan          30 auerbach
 31 diabetic            32 diabolic            33 drawback            34 fabric              35 fabricate
 36 flashback           37 halfback            38 iambic              39 lampblack           40 leatherback
 41 metabolic           42 nabisco             43 paperback           44 parabolic           45 playback
 46 prefabricate        47 quarterback         48 razorback           49 roadblock           50 sabbatical
 51 snapback            52 strabismic          53 syllabic            54 tabernacle          55 tablecloth

With command line argument "alw":

  1 afterglow            2 airflow              3 alewife              4 allentown            5 alleyway
  6 allow                7 allowance            8 alway                9 always              10 baldwin
 11 barlow              12 bartholomew         13 bungalow            14 caldwell            15 candlewick
 16 cauliflower         17 fallow              18 foamflower          19 galloway            20 gallows
 21 galway              22 halfway             23 hallow              24 halloween           25 hallway
 26 malawi              27 mallow              28 marlowe             29 marshmallow         30 mayflower
 31 metalwork           32 railway             33 sallow              34 saltwater           35 sandalwood
 36 shadflower          37 shallow             38 stalwart            39 tailwind            40 tallow

C++

#include <cstdlib>
#include <fstream>
#include <iostream>

bool is_abc_word(const std::string& word) {
    bool a = false;
    bool b = false;
    for (char ch : word) {
        switch (ch) {
        case 'a':
            if (!a)
                a = true;
            break;
        case 'b':
            if (!b) {
                // fail if we haven't seen 'a' yet
                if (!a)
                    return false;
                b = true;
            }
            break;
        case 'c':
            // succeed iff we've seen 'b' already
            return b;
        }
    }
    return false;
}

int main(int argc, char** argv) {
    const char* filename(argc < 2 ? "unixdict.txt" : argv[1]);
    std::ifstream in(filename);
    if (!in) {
        std::cerr << "Cannot open file '" << filename << "'.\n";
        return EXIT_FAILURE;
    }
    std::string word;
    int n = 1;
    while (getline(in, word)) {
        if (is_abc_word(word))
            std::cout << n++ << ": " << word << '\n';
    }
    return EXIT_SUCCESS;
}
Output:
1: aback
2: abacus
3: abc
4: abdicate
5: abduct
6: abeyance
7: abject
8: abreact
9: abscess
10: abscissa
11: abscissae
12: absence
13: abstract
14: abstracter
15: abstractor
16: adiabatic
17: aerobacter
18: aerobic
19: albacore
20: alberich
21: albrecht
22: algebraic
23: alphabetic
24: ambiance
25: ambuscade
26: aminobenzoic
27: anaerobic
28: arabic
29: athabascan
30: auerbach
31: diabetic
32: diabolic
33: drawback
34: fabric
35: fabricate
36: flashback
37: halfback
38: iambic
39: lampblack
40: leatherback
41: metabolic
42: nabisco
43: paperback
44: parabolic
45: playback
46: prefabricate
47: quarterback
48: razorback
49: roadblock
50: sabbatical
51: snapback
52: strabismic
53: syllabic
54: tabernacle
55: tablecloth

CLU

abc_word = proc (s: string) returns (bool)
    a: int := string$indexc('a', s)
    b: int := string$indexc('b', s)
    c: int := string$indexc('c', s)
    
    return(a>0 cand b>a cand c>b)
end abc_word

start_up = proc () 
    po: stream := stream$primary_output()
    dict: stream := stream$open(file_name$parse("unixdict.txt"), "read")
    while true do
        word: string := stream$getl(dict)
        if abc_word(word) then stream$putl(po, word) end
    end except when end_of_file: end
    stream$close(dict)
end start_up
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

COBOL

       IDENTIFICATION DIVISION.
       PROGRAM-ID. ABC-WORDS.
       
       ENVIRONMENT DIVISION.
       INPUT-OUTPUT SECTION.
       FILE-CONTROL.
           SELECT DICT ASSIGN TO DISK
           ORGANIZATION LINE SEQUENTIAL.
           
       DATA DIVISION.
       FILE SECTION.
       FD DICT 
           LABEL RECORD STANDARD
           VALUE OF FILE-ID IS "unixdict.txt".
       01 WORD            PIC X(32).
       
       WORKING-STORAGE SECTION.
       01 A               PIC 99.
       01 B               PIC 99.
       01 C               PIC 99.
       01 X               PIC 99.
       
       PROCEDURE DIVISION.
       BEGIN.
           OPEN INPUT DICT.
           
       READ-WORD.
           READ DICT, AT END CLOSE DICT, STOP RUN.
           PERFORM CHECK-WORD.
           GO TO READ-WORD.
           
       CHECK-WORD.
           MOVE ZERO TO A, B, C, X.
           INSPECT WORD TALLYING A FOR CHARACTERS BEFORE INITIAL 'a'.
           INSPECT WORD TALLYING B FOR CHARACTERS BEFORE INITIAL 'b'.
           INSPECT WORD TALLYING C FOR CHARACTERS BEFORE INITIAL 'c'.
           INSPECT WORD TALLYING X FOR CHARACTERS BEFORE INITIAL ' '.
           IF A IS LESS THAN B 
           AND B IS LESS THAN C 
           AND C IS LESS THAN X,
               DISPLAY WORD.
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Delphi

Translation of: C#
program ABC_words;

{$APPTYPE CONSOLE}

uses
  System.SysUtils,
  System.IoUtils;

var
  bi, ai, i: Integer;
  chars, item: string;
  ch: char;
  skip: boolean;

begin
  bi := 0;
  i := 0;
  chars := 'abc';

  if ParamCount > 0 then
    chars := ParamStr(1);

  writeln('Search words with letters "', chars, '"  in alphabetical order'#10);

  for item in TFile.ReadAllLines('unixdict.txt') do
  begin
    ai := -1;
    skip := false;
    for ch in chars do
    begin
      bi := item.IndexOf(ch);
      if bi > ai then
      begin
        ai := bi;
      end
      else
      begin
        skip := true;
        Break;
      end;
    end;

    if not skip then
    begin
      inc(i);
      write(i: 3, ' ', item.PadRight(18));
      if i mod 5 = 0 then
        writeln;
    end;
  end;
    

  {$IFNDEF UNIX} readln; {$ENDIF}
end.

Diego

add_ary({str},foundWords);
with_file()
    ()_read⟦{raw},unixdict.txt⟧_splitto(words,⟦\n⟧)
        (words)_if⟦[posA]<[posB]<[posC]⟧)_findto(posA,⟦a⟧)_i⟪0⟫_findto(posB,⟦b⟧)_i⟪0⟫_findto(posC,⟦c⟧)_i⟪0⟫
            ?_(foundWords)_add⟦words⟪⟫⟧;
        ;
    ;
;
log_console()_(foundWords);

Alternatively...

add_ary({str},foundWords);
with_file()
    ()_read⟦{raw},unixdict.txt⟧_splitto(words,⟦\n⟧)
        (words)_foreach(word)
            ?_(word)_findto(posA,⟦a⟧)_i⟪0⟫;
            ?_(word)_sliceto(foundA,⟦[posA]⟧)
                ?_(foundA)_findto(posB,⟦b⟧)_i⟪0⟫;
                ?_(foundA)_sliceto(foundB,⟦[posB]⟧)
                    ?_(foundB)_find⟦c⟧
                        ?_(foundWords)_add[word];
                    ;
                ;
            ;
        ;
    ;
;
log_console()_(foundWords);

Output:

aback,abacus,abc,abdicate,abduct,abeyance,abject,abreact,abscess,abscissa,abscissae,absence,abstract,abstracter,abstractor,adiabatic,aerobacter,aerobic,albacore,alberich,albrecht,algebraic,alphabetic,ambiance,ambuscade,aminobenzoic,anaerobic,arabic,athabascan,auerbach,diabetic,diabolic,drawback,fabric,fabricate,flashback,halfback,iambic,lampblack,leatherback,metabolic,nabisco,paperback,parabolic,playback,prefabricate,quarterback,razorback,roadblock,sabbatical,snapback,strabismic,syllabic,tabernacle,tablecloth

Draco

\util.g

proc nonrec abc_word(*char line) bool:
    int a, b, c;
    a := CharsIndex(line, "a");
    b := CharsIndex(line, "b");
    c := CharsIndex(line, "c");
    a ~= -1 and a < b and b < c
corp

proc nonrec main() void:
    file(1024) dictfile;
    [32] char buf;
    *char line;
    channel input text dict;
    
    open(dict, dictfile, "unixdict.txt");
    line := &buf[0];
    
    while readln(dict; line) do
        if abc_word(line) then writeln(line) fi
    od;
    
    close(dict)
corp
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

DuckDB

Works with: DuckDB version V1.0

Using a regex

select column0 as abc
from read_csv_auto('unixdict.txt', header=false, sep='\t')
where regexp_matches(column0, '^[^bc]*a[^c]*b.*c');
Output:

as below.

Avoiding regex

create or replace function is_abc_word(word) as (
  with cte as (
    select instr(word,'a') as a, instr(word,'b') as b, instr(word,'c') as c
  )
  select ( 0 < a and a < b and b < c) 
  from cte
);

select column0 as abc
from read_csv_auto('unixdict.txt', header=false, sep='\t')
where is_abc_word(column0);
Output:

Synopsis:

┌──────────────┐
│     abc      │
│   varchar    │
├──────────────┤
│ aback        │
│ abacus       │
│ abc          │
│ abdicate     │
...
│ tablecloth   │
├──────────────┤
│   55 rows    │
│  (40 shown)  │
└──────────────┘

EasyLang

repeat
   s$ = input
   until s$ = ""
   a = strpos s$ "a"
   b = strpos s$ "b"
   c = strpos s$ "c"
   if a > 0 and b > a and c > b
      print s$
   .
.
# 
# the content of unixdict.txt 
input_data
10th
drawback
fabric

ed

# by Artyom Bologov
H
v/^[^abc]*a[^bc]*b[^c]*c/d
,p
Q
Output:
$ ed -s unixdict.txt < abc.ed 
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth


F#

// ABC words. Nigel Galloway: August 29th., 2024
let isABC n=System.Text.RegularExpressions.Regex.Match(n,"^[^bc]*a[^c]*b.*c").Value.Length>0
System.IO.File.ReadLines "unixdict.txt"|>Seq.filter izABC|>Seq.iter(printfn "%s")
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Factor

USING: grouping io.encodings.ascii io.files kernel prettyprint
sequences sets ;

"unixdict.txt" ascii file-lines
[ "abc" within members "abc" = ] filter
5 group simple-table.
Output:
aback        abacus      abc        abdicate   abduct
abeyance     abject      abreact    abscess    abscissa
abscissae    absence     abstract   abstracter abstractor
adiabatic    aerobacter  aerobic    albacore   alberich
albrecht     algebraic   alphabetic ambiance   ambuscade
aminobenzoic anaerobic   arabic     athabascan auerbach
diabetic     diabolic    drawback   fabric     fabricate
flashback    halfback    iambic     lampblack  leatherback
metabolic    nabisco     paperback  parabolic  playback
prefabricate quarterback razorback  roadblock  sabbatical
snapback     strabismic  syllabic   tabernacle tablecloth

Forth

Works with: Gforth
: abc-word? ( addr u -- ? )
  false false { a b }
  0 do
    dup c@ case
      'a' of true to a endof
      'b' of a invert if unloop drop false exit then true to b endof
      'c' of unloop drop b exit endof
    endcase
    1+
  loop
  drop
  false ;

256 constant max-line

: main
  0 0 { count fd-in }
  s" unixdict.txt" r/o open-file throw to fd-in
  begin
    here max-line fd-in read-line throw
  while
    here swap 2dup abc-word? if
      count 1+ to count
      count 2 .r ." : " type cr
    else
      2drop
    then
  repeat
  drop
  fd-in close-file throw ;

main
bye
Output:
 1: aback
 2: abacus
 3: abc
 4: abdicate
 5: abduct
 6: abeyance
 7: abject
 8: abreact
 9: abscess
10: abscissa
11: abscissae
12: absence
13: abstract
14: abstracter
15: abstractor
16: adiabatic
17: aerobacter
18: aerobic
19: albacore
20: alberich
21: albrecht
22: algebraic
23: alphabetic
24: ambiance
25: ambuscade
26: aminobenzoic
27: anaerobic
28: arabic
29: athabascan
30: auerbach
31: diabetic
32: diabolic
33: drawback
34: fabric
35: fabricate
36: flashback
37: halfback
38: iambic
39: lampblack
40: leatherback
41: metabolic
42: nabisco
43: paperback
44: parabolic
45: playback
46: prefabricate
47: quarterback
48: razorback
49: roadblock
50: sabbatical
51: snapback
52: strabismic
53: syllabic
54: tabernacle
55: tablecloth

FreeBASIC

#define NOTINSTRING 9999

function first_occ( s as string, letter as string ) as uinteger
    for i as ubyte = 1 to len(s)
        if mid(s,i,1) = letter then return i
    next i
    return NOTINSTRING - asc(letter)
end function

function is_abc( s as string ) as boolean
    if first_occ( s, "a" ) > first_occ( s, "b" ) then return false
    if first_occ( s, "b" ) > first_occ( s, "c" ) then return false
    if first_occ( s, "c" ) > len(s) then return false
    return true
end function

dim as string word
dim as uinteger c = 0

open "unixdict.txt" for input as #1
while true
    line input #1, word
    if word="" then exit while
    if is_abc( word ) then
        c+=1
        print c;".   ";word
    end if
wend
close #1
Output:
1.   aback
2.   abacus
3.   abc
4.   abdicate
5.   abduct
6.   abeyance
7.   abject
8.   abreact
9.   abscess
10.   abscissa
11.   abscissae
12.   absence
13.   abstract
14.   abstracter
15.   abstractor
16.   adiabatic
17.   aerobacter
18.   aerobic
19.   albacore
20.   alberich
21.   albrecht
22.   algebraic
23.   alphabetic
24.   ambiance
25.   ambuscade
26.   aminobenzoic
27.   anaerobic
28.   arabic
29.   athabascan
30.   auerbach
31.   diabetic
32.   diabolic
33.   drawback
34.   fabric
35.   fabricate
36.   flashback
37.   halfback
38.   iambic
39.   lampblack
40.   leatherback
41.   metabolic
42.   nabisco
43.   paperback
44.   parabolic
45.   playback
46.   prefabricate
47.   quarterback
48.   razorback
49.   roadblock
50.   sabbatical
51.   snapback
52.   strabismic
53.   syllabic
54.   tabernacle
55.   tablecloth

FutureBasic

include "NSLog.incl"

local fn WordList as CFArrayRef
  CFArrayRef wordList = NULL
  CFURLRef url = fn URLWithString( @"http://wiki.puzzlers.org/pub/wordlists/unixdict.txt" )
  CFStringRef string = fn StringWithContentsOfURL( url, NSUTF8StringEncoding, NULL )
  if ( string ) then wordList = fn StringComponentsSeparatedByCharactersInSet( string, fn CharacterSetNewlineSet )
end fn = wordList

void local fn ABCWords
  CFArrayRef  list = fn WordList
  CFStringRef string
  long        abc

  if ( list ) == NULL then NSLog(@"Unable to load word list") : exit fn
  for string in list
    abc = instr( 0,   string, @"a")
    if ( abc == NSNotFound ) then continue
    abc = instr( abc, string, @"b")
    if ( abc == NSNotFound ) then continue
    abc = instr( abc, string, @"c")
    if ( abc != NSNotFound ) then NSLog(@"%@",string)
  next
end fn

fn ABCWords

HandleEvents
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Go

package main

import (
    "bytes"
    "fmt"
    "io/ioutil"
    "log"
)

func main() {
    wordList := "unixdict.txt"
    b, err := ioutil.ReadFile(wordList)
    if err != nil {
        log.Fatal("Error reading file")
    }
    bwords := bytes.Fields(b)
    count := 0
    fmt.Println("Based on first occurrences only, the ABC words in", wordList, "are:")
    for _, bword := range bwords {
        a := bytes.IndexRune(bword, 'a')
        b := bytes.IndexRune(bword, 'b')
        c := bytes.IndexRune(bword, 'c')
        if a >= 0 && b > a && c > b {
            count++
            fmt.Printf("%2d: %s\n", count, string(bword))
        }
    }
}
Output:
Based on first occurrences only, the ABC words in unixdict.txt are:
 1: aback
 2: abacus
 3: abc
 4: abdicate
 5: abduct
 6: abeyance
 7: abject
 8: abreact
 9: abscess
10: abscissa
11: abscissae
12: absence
13: abstract
14: abstracter
15: abstractor
16: adiabatic
17: aerobacter
18: aerobic
19: albacore
20: alberich
21: albrecht
22: algebraic
23: alphabetic
24: ambiance
25: ambuscade
26: aminobenzoic
27: anaerobic
28: arabic
29: athabascan
30: auerbach
31: diabetic
32: diabolic
33: drawback
34: fabric
35: fabricate
36: flashback
37: halfback
38: iambic
39: lampblack
40: leatherback
41: metabolic
42: nabisco
43: paperback
44: parabolic
45: playback
46: prefabricate
47: quarterback
48: razorback
49: roadblock
50: sabbatical
51: snapback
52: strabismic
53: syllabic
54: tabernacle
55: tablecloth

Haskell

import Data.List (elemIndex)
import Data.Maybe (isJust)

------------------------ ABC WORDS -----------------------

isABC :: String -> Bool
isABC s =
  isJust $
    residue "bc" 'a' s
      >>= residue "c" 'b' 
      >>= elemIndex 'c'

residue :: String -> Char -> String -> Maybe String
residue except c = go
  where
    go [] = Nothing
    go (x : xs)
      | x `elem` except = Nothing
      | c == x = Just xs
      | otherwise = go xs

--------------------------- TEST -------------------------
main :: IO ()
main =
  readFile "unixdict.txt"
    >>= mapM_ print . zip [1 ..] . filter isABC . lines
Output:
(1,"aback")
(2,"abacus")
(3,"abc")
(4,"abdicate")
(5,"abduct")
(6,"abeyance")
(7,"abject")
(8,"abreact")
(9,"abscess")
(10,"abscissa")
(11,"abscissae")
(12,"absence")
(13,"abstract")
(14,"abstracter")
(15,"abstractor")
(16,"adiabatic")
(17,"aerobacter")
(18,"aerobic")
(19,"albacore")
(20,"alberich")
(21,"albrecht")
(22,"algebraic")
(23,"alphabetic")
(24,"ambiance")
(25,"ambuscade")
(26,"aminobenzoic")
(27,"anaerobic")
(28,"arabic")
(29,"athabascan")
(30,"auerbach")
(31,"diabetic")
(32,"diabolic")
(33,"drawback")
(34,"fabric")
(35,"fabricate")
(36,"flashback")
(37,"halfback")
(38,"iambic")
(39,"lampblack")
(40,"leatherback")
(41,"metabolic")
(42,"nabisco")
(43,"paperback")
(44,"parabolic")
(45,"playback")
(46,"prefabricate")
(47,"quarterback")
(48,"razorback")
(49,"roadblock")
(50,"sabbatical")
(51,"snapback")
(52,"strabismic")
(53,"syllabic")
(54,"tabernacle")
(55,"tablecloth")

Java

import java.io.BufferedReader;
import java.io.FileReader;

public class AbcWords {
    public static void main(String[] args) {
        String fileName = "unixdict.txt";
        String chars = "abc";
        for (int i = 0; i + 1 < args.length
                && args[i].length() > 1
                && args[i].charAt(0) == '-'; ++i) {
            switch (args[i].charAt(1)) {
            case 'f':
                fileName = args[++i];
                break;
            case 'c':
                chars = args[++i];
                break;
            }
        }
        
        try (BufferedReader reader = new BufferedReader(new FileReader(fileName))) {
            String line;
            int n = 0;
            while ((line = reader.readLine()) != null) {
                if (match(line, chars)) {
                    ++n;
                    System.out.printf("%3d: %-20s", n, line);
                    if (n % 3 == 0)
                        System.out.println();
                }
            }
            if (n > 0 && n % 3 != 0)
                System.out.println();
        } catch (Exception e)  {
            e.printStackTrace();
        }
    }

    // Returns true if word contains every character in chars in the
    // same order. chars may contain the same character more than once.
    private static boolean match(String word, String chars) {
        int length = chars.length();
        boolean[] seen = new boolean[length];
        int wordLength = word.length();
        for (int w = 0; w < wordLength; ++w) {
            char ch = word.charAt(w);
            int index = -1;
            for (int c = 0; c < length; ++c) {
                if (ch == chars.charAt(c) && !seen[c]) {
                    index = c;
                    break;
                }
            }
            if (index == -1)
                continue;
            if (index + 1 == length)
                return index == 0 ? true : seen[index - 1];
            if (index > 0 && !seen[index - 1])
                return false;
            seen[index] = true;
        }
        return false;
    }
}
Output:

With no command line arguments:

  1: aback                 2: abacus                3: abc                 
  4: abdicate              5: abduct                6: abeyance            
  7: abject                8: abreact               9: abscess             
 10: abscissa             11: abscissae            12: absence             
 13: abstract             14: abstracter           15: abstractor          
 16: adiabatic            17: aerobacter           18: aerobic             
 19: albacore             20: alberich             21: albrecht            
 22: algebraic            23: alphabetic           24: ambiance            
 25: ambuscade            26: aminobenzoic         27: anaerobic           
 28: arabic               29: athabascan           30: auerbach            
 31: diabetic             32: diabolic             33: drawback            
 34: fabric               35: fabricate            36: flashback           
 37: halfback             38: iambic               39: lampblack           
 40: leatherback          41: metabolic            42: nabisco             
 43: paperback            44: parabolic            45: playback            
 46: prefabricate         47: quarterback          48: razorback           
 49: roadblock            50: sabbatical           51: snapback            
 52: strabismic           53: syllabic             54: tabernacle          
 55: tablecloth

With command line arguments "-c pmm":

  1: anthropomorphism      2: epigrammatic          3: epimorphism         
  4: euphemism             5: optimism              6: optimum             
  7: pandemonium           8: pantomime             9: pantomimic          
 10: pemmican             11: persimmon            12: pessimism           
 13: pessimum             14: plummet              15: postmortem          
 16: pragmatism           17: praseodymium         18: premium             
 19: primitivism          20: programmable         21: programmed          
 22: programmer           23: programming          24: promethium          
 25: pummel               26: supremum

JavaScript

(() => {
    "use strict";

    // -------------------- ABC WORDS --------------------

    // isABC :: String -> Bool
    const isABC = s =>
        // True if the string contains each of 'a' 'b' 'c',
        // and their first occurrences in the string are
        // in that alphabetical order.
        bind(
            bind(
                residue("a")("bc")(s)
            )(
                residue("b")("c")
            )
        )(
            r => r.includes("c") || null
        ) !== null;


    // residue :: Char -> String -> String -> Maybe String
    const residue = c =>
        // Any characters remaining in a given string
        // after the first occurrence of c, or null
        // if c is not found, or is preceded by any
        // excluded characters.
        excluded => {
            const go = t =>
                (0 < t.length) ? (() => {
                    const x = t[0];

                    return excluded.includes(x) ? (
                        null
                    ) : c === x ? (
                        t.slice(1)
                    ) : go(t.slice(1));
                })() : null;

            return go;
        };


    // ---------------------- TEST -----------------------
    const main = () =>
        lines(readFile("~/unixdict.txt"))
        .filter(isABC)
        .map((x, i) => `(${1 + i}, ${x})`)
        .join("\n");


    // --------------------- GENERIC ---------------------

    // bind (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
    const bind = mb =>
    // Null if mb is null, or the application of the
    // (a -> Maybe b) function mf to the contents of mb.
        mf => null === mb ? (
            mb
        ) : mf(mb);


    // lines :: String -> [String]
    const lines = s =>
    // A list of strings derived from a single string
    // which is delimited by \n or by \r\n or \r.
        Boolean(s.length) ? (
            s.split(/\r\n|\n|\r/u)
        ) : [];


    // readFile :: FilePath -> IO String
    const readFile = fp => {
    // The contents of a text file at the
    // given file path.
        const
            e = $(),
            ns = $.NSString
            .stringWithContentsOfFileEncodingError(
                $(fp).stringByStandardizingPath,
                $.NSUTF8StringEncoding,
                e
            );

        return ObjC.unwrap(
            ns.isNil() ? (
                e.localizedDescription
            ) : ns
        );
    };


    // MAIN ---
    return main();
})();
Output:
(1, aback)
(2, abacus)
(3, abc)
(4, abdicate)
(5, abduct)
(6, abeyance)
(7, abject)
(8, abreact)
(9, abscess)
(10, abscissa)
(11, abscissae)
(12, absence)
(13, abstract)
(14, abstracter)
(15, abstractor)
(16, adiabatic)
(17, aerobacter)
(18, aerobic)
(19, albacore)
(20, alberich)
(21, albrecht)
(22, algebraic)
(23, alphabetic)
(24, ambiance)
(25, ambuscade)
(26, aminobenzoic)
(27, anaerobic)
(28, arabic)
(29, athabascan)
(30, auerbach)
(31, diabetic)
(32, diabolic)
(33, drawback)
(34, fabric)
(35, fabricate)
(36, flashback)
(37, halfback)
(38, iambic)
(39, lampblack)
(40, leatherback)
(41, metabolic)
(42, nabisco)
(43, paperback)
(44, parabolic)
(45, playback)
(46, prefabricate)
(47, quarterback)
(48, razorback)
(49, roadblock)
(50, sabbatical)
(51, snapback)
(52, strabismic)
(53, syllabic)
(54, tabernacle)
(55, tablecloth)

J

A word is an abc word if the order of the indices of 'a', 'b' and 'c' and the final letter of the word are unchanged by sorting. (The index of 'a' would be the length of the word -- one greater than the last index into the word -- if 'a' was missing from the word. So by including that last index in our list of indices to be sorted, we eliminate all words which are missing an 'a', 'b' or 'c'.)

   >(#~ (-: /:~)@(<:@#,~i.&'abc')@>) cutLF tolower fread 'unixdict.txt'
aback       
abacus      
abc         
abdicate    
abduct      
abeyance    
abject      
abreact     
abscess     
abscissa    
abscissae   
absence     
abstract    
abstracter  
abstractor  
adiabatic   
aerobacter  
aerobic     
albacore    
alberich    
albrecht    
algebraic   
alphabetic  
ambiance    
ambuscade   
aminobenzoic
anaerobic   
arabic      
athabascan  
auerbach    
diabetic    
diabolic    
drawback    
fabric      
fabricate   
flashback   
halfback    
iambic      
lampblack   
leatherback 
metabolic   
nabisco     
paperback   
parabolic   
playback    
prefabricate
quarterback 
razorback   
roadblock   
sabbatical  
snapback    
strabismic  
syllabic    
tabernacle  
tablecloth

jq

Works with: jq

Works with gojq, the Go implementation of jq

def is_abc_word:
  [index("a", "b", "c")]
  | all(.[]; . != null) and .[0] < .[1] and .[1] < .[2] ;

select(is_abc_word)

Invocation: jq -rR -f abc-words.jq unixdict.txt

Output:

(synopsis)

aback
abacus
abc
...
syllabic
tabernacle
tablecloth

Julia

See Alternade_words#Julia for the foreachword function.

function isabcword(w, _)
    positions = [findfirst(c -> c == ch, w) for ch in "abc"]
    return all(!isnothing, positions) && issorted(positions) ? w : ""
end

foreachword("unixdict.txt", isabcword)
Output:
Word source: unixdict.txt

aback          abacus         abc            abdicate       abduct         abeyance       
abject         abreact        abscess        abscissa       abscissae      absence
abstract       abstracter     abstractor     adiabatic      aerobacter     aerobic
albacore       alberich       albrecht       algebraic      alphabetic     ambiance
ambuscade      aminobenzoic   anaerobic      arabic         athabascan     auerbach       
diabetic       diabolic       drawback       fabric         fabricate      flashback
halfback       iambic         lampblack      leatherback    metabolic      nabisco
paperback      parabolic      playback       prefabricate   quarterback    razorback      
roadblock      sabbatical     snapback       strabismic     syllabic       tabernacle
tablecloth

Lua

for word in io.lines('unixdict.txt') do
  if string.find(word, "^[^bc]*a[^c]*b.*c") then
    print(word)
  end
end

Mathematica /Wolfram Language

ClearAll[unixdictWords, abcStringQ];

unixdictWords = StringSplit@Import["https://web.archive.org/web/20180611003215/http://www.puzzlers.org/pub/wordlists/unixdict.txt"];

abcStringQ[s_String] := StringMatchQ[s, ___ ~~ "a" ~~ ___ ~~ "b" ~~ ___ ~~ "c" ~~ ___];

Select[abcStringQ][unixdictWords]
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
acerbic
acrobacy
acrobatic
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
babcock
barbaric
barbecue
cambric
camelback
canvasback
carbonaceous
carbonic
carboxylic
carbuncle
catabolic
claustrophobic
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Modula-2

MODULE ABCWords;
IMPORT SeqIO;
IMPORT Texts;
FROM InOut IMPORT WriteString, WriteLn;
FROM Strings IMPORT Pos;

VAR file: SeqIO.FILE;
    dict: Texts.TEXT;
    word: ARRAY [0..63] OF CHAR;
    fs: SeqIO.FileState;
    ts: Texts.TextState;
    
PROCEDURE IsABCWord(word: ARRAY OF CHAR): BOOLEAN;
    VAR a, b, c, missing: CARDINAL;
BEGIN
    missing := Pos("", word);
    a := Pos("a", word);
    b := Pos("b", word);
    c := Pos("c", word);
    RETURN (a # missing) 
       AND (b # missing) 
       AND (c # missing)
       AND (a < b) 
       AND (b < c);    
END IsABCWord;

BEGIN
    fs := SeqIO.Open(file, "unixdict.txt");
    ts := Texts.Connect(dict, file);
    
    WHILE NOT Texts.EOT(dict) DO
        Texts.ReadLn(dict, word);
        IF IsABCWord(word) THEN
             WriteString(word);
             WriteLn();
        END;
    END;
    
    ts := Texts.Disconnect(dict);
    fs := SeqIO.Close(file);
END ABCWords.
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Nim

import strutils

func isAbcWord(word: string): bool =
  let ia = word.find('a')
  if ia < 0: return false
  let ib = word.find('b')
  if ib < ia: return false
  let ic = word.find('c')
  if ic < ib: return false
  result = true

var count = 0
for word in "unixdict.txt".lines:
  if word.isAbcWord:
    inc count
    echo ($count).align(2), ' ', word
Output:
 1 aback
 2 abacus
 3 abc
 4 abdicate
 5 abduct
 6 abeyance
 7 abject
 8 abreact
 9 abscess
10 abscissa
11 abscissae
12 absence
13 abstract
14 abstracter
15 abstractor
16 adiabatic
17 aerobacter
18 aerobic
19 albacore
20 alberich
21 albrecht
22 algebraic
23 alphabetic
24 ambiance
25 ambuscade
26 aminobenzoic
27 anaerobic
28 arabic
29 athabascan
30 auerbach
31 diabetic
32 diabolic
33 drawback
34 fabric
35 fabricate
36 flashback
37 halfback
38 iambic
39 lampblack
40 leatherback
41 metabolic
42 nabisco
43 paperback
44 parabolic
45 playback
46 prefabricate
47 quarterback
48 razorback
49 roadblock
50 sabbatical
51 snapback
52 strabismic
53 syllabic
54 tabernacle
55 tablecloth

Nu

open 'unixdict.txt' | split words | where $it =~ '(?i)^[^abc]*a[^bc]*b[^c]*c'
Output:
╭────┬──────────────╮
│  0 │ aback        │
│  1 │ abacus       │
│  2 │ abc          │
│  3 │ abdicate     │
│  4 │ abduct       │
│  5 │ abeyance     │
│  6 │ abject       │
│  7 │ abreact      │
│  8 │ abscess      │
│  9 │ abscissa     │
│ 10 │ abscissae    │
│ 11 │ absence      │
│ 12 │ abstract     │
│ 13 │ abstracter   │
│ 14 │ abstractor   │
│ 15 │ adiabatic    │
│ 16 │ aerobacter   │
│ 17 │ aerobic      │
│ 18 │ albacore     │
│ 19 │ alberich     │
│ 20 │ albrecht     │
│ 21 │ algebraic    │
│ 22 │ alphabetic   │
│ 23 │ ambiance     │
│ 24 │ ambuscade    │
│ 25 │ aminobenzoic │
│ 26 │ anaerobic    │
│ 27 │ arabic       │
│ 28 │ athabascan   │
│ 29 │ auerbach     │
│ 30 │ diabetic     │
│ 31 │ diabolic     │
│ 32 │ drawback     │
│ 33 │ fabric       │
│ 34 │ fabricate    │
│ 35 │ flashback    │
│ 36 │ halfback     │
│ 37 │ iambic       │
│ 38 │ lampblack    │
│ 39 │ leatherback  │
│ 40 │ metabolic    │
│ 41 │ nabisco      │
│ 42 │ paperback    │
│ 43 │ parabolic    │
│ 44 │ playback     │
│ 45 │ prefabricate │
│ 46 │ quarterback  │
│ 47 │ razorback    │
│ 48 │ roadblock    │
│ 49 │ sabbatical   │
│ 50 │ snapback     │
│ 51 │ strabismic   │
│ 52 │ syllabic     │
│ 53 │ tabernacle   │
│ 54 │ tablecloth   │
╰────┴──────────────╯

Pascal

Free Pascal

Program abcwords;
uses Classes;

const
  FNAME = 'unixdict.txt';

var
  list: TStringList;
  str : string;
  a,b,c : integer;


begin
  list := TStringList.Create;
  list.LoadFromFile(FNAME);
  for str in list do
  begin
    a := pos('a',str);
    b := pos('b',str);
    c := pos('c',str);
    if (a>0) and (b>a) and (c > b) then writeln(str); 
   end;   
end.
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

PascalABC.NET

Translation of: F#
// ABC words. Nigel Galloway: August 29th., 2024
##
var izABC:string->boolean:=n->System.Text.RegularExpressions.Regex.Match(n,'^[^bc]*a[^c]*b.*c').Value.Length>0;
foreach s:string in System.IO.File.ReadLines('unixdict.txt') do if izABC(s) then println(s);
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Perl

Outputs same 55 words everyone else finds.

#!/usr/bin/perl

@ARGV = 'unixdict.txt';
print grep /^[^bc]*a[^c]*b.*c/, <>;

Phix

with javascript_semantics
function abc(string word) 
    integer {ia,ib,ic} = apply(true,find,{"abc",{word}})
    return ia>0 and ib>ia and ic>ib
end function
sequence words = filter(unix_dict(),abc)
printf(1,"%d abc words found: %s\n",{length(words),join(shorten(words,"",3),", ")})
Output:
55 abc words found: aback, abacus, abc, ..., syllabic, tabernacle, tablecloth

PL/I

abcWords: procedure options(main);
    declare dict file;
    open file(dict) title('unixdict.txt');
    on endfile(dict) stop;
    
    declare word char(32) varying, col fixed;
    col = 0;
    do while('1'b);
        get file(dict) list(word);
        
        declare (a, b, c) fixed;
        a = index(word, 'a');
        b = index(word, 'b');
        c = index(word, 'c');
        
        if a ^= 0 & b ^= 0 & c ^= 0 & a < b & b < c then do;
            put edit(word) (A(15));
            col = col + 1;
            if col = 5 then do;
                put skip;
                col = 0;
            end;
        end;
    end;    
end abcWords;
Output:
aback          abacus         abc            abdicate       abduct
abeyance       abject         abreact        abscess        abscissa
abscissae      absence        abstract       abstracter     abstractor
adiabatic      aerobacter     aerobic        albacore       alberich
albrecht       algebraic      alphabetic     ambiance       ambuscade
aminobenzoic   anaerobic      arabic         athabascan     auerbach
diabetic       diabolic       drawback       fabric         fabricate
flashback      halfback       iambic         lampblack      leatherback
metabolic      nabisco        paperback      parabolic      playback
prefabricate   quarterback    razorback      roadblock      sabbatical
snapback       strabismic     syllabic       tabernacle     tablecloth

Processing

String[] words;

void setup() {
  words = loadStrings("unixdict.txt");
  int count = 1;
  for (int i = 0; i < words.length; i++) {
    if (isAbcWord(words[i])) {
      println(count + " " + words[i]);
      count++;
    }
  }
}

boolean isAbcWord(String word) {
  if (word.contains("a") && word.indexOf("a") < word.indexOf("b") && word.indexOf("b") < word.indexOf("c")) {
    return true;
  }
  return false;
}
Output:
1 aback
2 abacus
3 abc
4 abdicate
5 abduct
6 abeyance
7 abject
8 abreact
9 abscess
10 abscissa
11 abscissae
12 absence
13 abstract
14 abstracter
15 abstractor
16 adiabatic
17 aerobacter
18 aerobic
19 albacore
20 alberich
21 albrecht
22 algebraic
23 alphabetic
24 ambiance
25 ambuscade
26 aminobenzoic
27 anaerobic
28 arabic
29 athabascan
30 auerbach
31 diabetic
32 diabolic
33 drawback
34 fabric
35 fabricate
36 flashback
37 halfback
38 iambic
39 lampblack
40 leatherback
41 metabolic
42 nabisco
43 paperback
44 parabolic
45 playback
46 prefabricate
47 quarterback
48 razorback
49 roadblock
50 sabbatical
51 snapback
52 strabismic
53 syllabic
54 tabernacle
55 tablecloth

Python

Outputs the same 55 words as other examples when entered in a Posix terminal shell

python -c '
import sys
for ln in sys.stdin:
    if "a" in ln and ln.find("a") < ln.find("b") < ln.find("c"):
        print(ln.rstrip())
' < unixdict.txt

Or a functionally composed variant, with a predicate which takes a single recursive pass through the characters of each word:

'''ABC Words'''


# isABC :: String -> Bool
def isABC(s):
    '''True if s contains 'a', 'b' and 'c', with the
       first occurrences of each in that order.
    '''
    return bind(
        bind(
            residue('bc', 'a')(s)
        )(
            residue('c', 'b')
        )
    )(
        lambda r: 'c' in r
    )


# residue (String, Char) -> String -> Maybe String
def residue(disallowed, c):
    '''Any characters remaining in s after c, unless
       c is preceded by excluded characters.
    '''
    def go(s):
        if s:
            x = s[0]
            return None if x in disallowed else (
                s[1:] if c == x else go(s[1:])
            )
        else:
            return None
    return go


# ------------------------- TEST -------------------------
# main :: IO ()
def main():
    '''All words matching the isABC predicate
       in a local copy of unixdict.txt
    '''
    for x in enumerate(
        filter(
            isABC,
            readFile('unixdict.txt').splitlines()
        ),
        start=1
    ):
        print(x)


# ----------------------- GENERIC ------------------------

# bind (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
def bind(m):
    '''Composition of a sequence of (a -> None | b) functions.
       If m is None, it is passed straight through.
       If m is x, the result is an application
       of the (a -> None | b) function (mf) to x.
    '''
    def go(mf):
        return m if None is m else mf(m)
    return go


# readFile :: FilePath -> IO String
def readFile(fp):
    '''The contents of any file at the path
       derived by expanding any ~ in fp.
    '''
    with open(fp, 'r', encoding='utf-8') as f:
        return f.read()


# MAIN ---
if __name__ == '__main__':
    main()
Output:
(1, 'aback')
(2, 'abacus')
(3, 'abc')
(4, 'abdicate')
(5, 'abduct')
(6, 'abeyance')
(7, 'abject')
(8, 'abreact')
(9, 'abscess')
(10, 'abscissa')
(11, 'abscissae')
(12, 'absence')
(13, 'abstract')
(14, 'abstracter')
(15, 'abstractor')
(16, 'adiabatic')
(17, 'aerobacter')
(18, 'aerobic')
(19, 'albacore')
(20, 'alberich')
(21, 'albrecht')
(22, 'algebraic')
(23, 'alphabetic')
(24, 'ambiance')
(25, 'ambuscade')
(26, 'aminobenzoic')
(27, 'anaerobic')
(28, 'arabic')
(29, 'athabascan')
(30, 'auerbach')
(31, 'diabetic')
(32, 'diabolic')
(33, 'drawback')
(34, 'fabric')
(35, 'fabricate')
(36, 'flashback')
(37, 'halfback')
(38, 'iambic')
(39, 'lampblack')
(40, 'leatherback')
(41, 'metabolic')
(42, 'nabisco')
(43, 'paperback')
(44, 'parabolic')
(45, 'playback')
(46, 'prefabricate')
(47, 'quarterback')
(48, 'razorback')
(49, 'roadblock')
(50, 'sabbatical')
(51, 'snapback')
(52, 'strabismic')
(53, 'syllabic')
(54, 'tabernacle')
(55, 'tablecloth')

Or using a regular expression.

import re
import textwrap

RE = re.compile(r"^([^bc\r\n]*a[^c\r\n]*b.*c.*)$", re.M)

with open("unixdict.txt") as fd:
    abc_words = RE.findall(fd.read())

print(f"found {len(abc_words)} ABC words")
print(textwrap.fill(" ".join(abc_words)))
Output:
found 55 ABC words
aback abacus abc abdicate abduct abeyance abject abreact abscess
abscissa abscissae absence abstract abstracter abstractor adiabatic
aerobacter aerobic albacore alberich albrecht algebraic alphabetic
ambiance ambuscade aminobenzoic anaerobic arabic athabascan auerbach
diabetic diabolic drawback fabric fabricate flashback halfback iambic
lampblack leatherback metabolic nabisco paperback parabolic playback
prefabricate quarterback razorback roadblock sabbatical snapback
strabismic syllabic tabernacle tablecloth

Quackery

  [ true swap 
    behead swap
    witheach 
      [ tuck < not if
          [ dip not 
            conclude ] ] 
    drop ]               is ascending ( [ --> b )

  [ [] swap 
    $ "abc" witheach
      [ over find 
        swap dip join ] 
     size join
     ascending ]         is abcword   ( $ --> b )
 
  [] 
  $ "rosetta/unixdict.txt" sharefile drop nest$
  witheach 
    [ dup abcword iff
        [ nested join ]
      else drop ] 
  dup size echo say " words found." cr
  70 wrap$
Output:
55 words found.

aback abacus abc abdicate abduct abeyance abject abreact abscess
abscissa abscissae absence abstract abstracter abstractor adiabatic
aerobacter aerobic albacore alberich albrecht algebraic alphabetic
ambiance ambuscade aminobenzoic anaerobic arabic athabascan auerbach
diabetic diabolic drawback fabric fabricate flashback halfback iambic
lampblack leatherback metabolic nabisco paperback parabolic playback
prefabricate quarterback razorback roadblock sabbatical snapback
strabismic syllabic tabernacle tablecloth

R

library(stringi)
library(dplyr)

check_abc <- function(w) {
  char_list <- stri_split_boundaries(w, type='character')[[1]]
  fpos   <- lapply(c("a","b","c"),\(x) grep(x,char_list)) %>% sapply(\(x) x[1])
  if (any(is.na(fpos)==T)) return(F)
  ifelse(all(sort(fpos) == fpos),T,F)
}

rep <- sapply(readLines("unixdict.txt"), \(x) check_abc(x))
print(names(rep[rep == T]))
Output:
[1] "aback"        "abacus"       "abc"          "abdicate"     "abduct"       "abeyance"    
 [7] "abject"       "abreact"      "abscess"      "abscissa"     "abscissae"    "absence"     
[13] "abstract"     "abstracter"   "abstractor"   "adiabatic"    "aerobacter"   "aerobic"     
[19] "albacore"     "alberich"     "albrecht"     "algebraic"    "alphabetic"   "ambiance"    
[25] "ambuscade"    "aminobenzoic" "anaerobic"    "arabic"       "athabascan"   "auerbach"    
[31] "diabetic"     "diabolic"     "drawback"     "fabric"       "fabricate"    "flashback"   
[37] "halfback"     "iambic"       "lampblack"    "leatherback"  "metabolic"    "nabisco"     
[43] "paperback"    "parabolic"    "playback"     "prefabricate" "quarterback"  "razorback"   
[49] "roadblock"    "sabbatical"   "snapback"     "strabismic"   "syllabic"     "tabernacle"  
[55] "tablecloth"  

Racket

#lang racket

(for ((i (in-naturals 1))
      (w (filter (curry regexp-match #rx"^[^bc]*a[^c]*b.*c.*$")
          (file->lines "../../data/unixdict.txt"))))
  (printf "~a\t~a~%" i w))
Output:

Output is elided... it's the same list of words in every other implementation

1	aback
2	abacus
3	abc
4	abdicate
5	abduct
6	abeyance
7	abject
8	abreact
9	abscess
10	abscissa
11	abscissae
12	absence
...
50	sabbatical
51	snapback
52	strabismic
53	syllabic
54	tabernacle
55	tablecloth

Raku

put display 'unixdict.txt'.IO.words».fc.grep({ (.index('a')//next) < (.index('b')//next) < (.index('c')//next) }),
     :11cols, :fmt('%-12s');

sub display ($list, :$cols = 10, :$fmt = '%6d', :$title = "{+$list} matching:\n" )   {
    cache $list;
    $title ~ $list.batch($cols)».fmt($fmt).join: "\n"
}
Output:
55 matching:
aback        abacus       abc          abdicate     abduct       abeyance     abject       abreact      abscess      abscissa     abscissae   
absence      abstract     abstracter   abstractor   adiabatic    aerobacter   aerobic      albacore     alberich     albrecht     algebraic   
alphabetic   ambiance     ambuscade    aminobenzoic anaerobic    arabic       athabascan   auerbach     diabetic     diabolic     drawback    
fabric       fabricate    flashback    halfback     iambic       lampblack    leatherback  metabolic    nabisco      paperback    parabolic   
playback     prefabricate quarterback  razorback    roadblock    sabbatical   snapback     strabismic   syllabic     tabernacle   tablecloth 

REXX

This REXX version doesn't care what order the words in the dictionary are in,   nor does it care what
case  (lower/upper/mixed)  the words are in,   the search for the   ABC   words is   caseless.

It also allows the   (ABC)   characters to be specified on the command line (CL) as well as the dictionary file identifier.

/*REXX program finds all the caseless alternade words (within an identified dictionary).*/
parse arg minL iFID .                            /*obtain optional arguments from the CL*/
if minL=='' | minL=="," then minL= 6             /*Not specified?  Then use the default.*/
if iFID=='' | iFID=="," then iFID='unixdict.txt' /* "      "         "   "   "     "    */
@.=                                              /*default value of any dictionary word.*/
            do #=1  while lines(iFID)\==0        /*read each word in the file  (word=X).*/
            x= strip( linein( iFID) )            /*pick off a word from the input line. */
            $.#= x;       upper x;       @.x= .  /*save: original case and the semaphore*/
            end   /*#*/                          /* [↑]   semaphore name is uppercased. */
#= # - 1                                         /*adjust word count because of DO loop.*/
finds= 0                                         /*count of the alternade words found.  */
say copies('─', 30)      #      "words in the dictionary file: "       iFID
say
        do j=1  for #;           L= length($.j)  /*process all the words that were found*/
        if L<minL  then iterate                  /*Is word too short?   Then ignore it. */
        p.=                                      /*initialize 2 parts of alternade word.*/
             do k=1  for L;         _= k // 2    /*build the  "   "    "      "      "  */
             p._= p._  ||  substr($.j, k, 1)     /*append to one part of alternade word.*/
             end   /*k*/

        parse upper value  p.0 p.1  with  p0 p1  /*obtain the uppercase alternade parts.*/
        if @.p0=='' | @.p1==''  then iterate     /*either parts of alternade not extant?*/
        finds= finds + 1                         /*bump the  count  of alternades found.*/
        say right(left($.j, 20), 25)    left(p.1, 10)    left(p.0, 10)   /*indent a bit.*/
        end        /*j*/
                                                 /*stick a fork in it,  we're all done. */
say copies('─',30)    finds   '  alternade words found with a minimum length of '    minL
output   when using the default input:
────────────────────────────── 25104 words in the dictionary file:  unixdict.txt
          aback
          abacus
          abc
          abdicate
          abduct
          abeyance
          abject
          abreact
          abscess
          abscissa
          abscissae
          absence
          abstract
          abstracter
          abstractor
          adiabatic
          aerobacter
          aerobic
          albacore
          alberich
          albrecht
          algebraic
          alphabetic
          ambiance
          ambuscade
          aminobenzoic
          anaerobic
          arabic
          athabascan
          auerbach
          diabetic
          diabolic
          drawback
          fabric
          fabricate
          flashback
          halfback
          iambic
          lampblack
          leatherback
          metabolic
          nabisco
          paperback
          parabolic
          playback
          prefabricate
          quarterback
          razorback
          roadblock
          sabbatical
          snapback
          strabismic
          syllabic
          tabernacle
          tablecloth
────────────────────────────── 55  "ABC" words found using the characters:  abc
output   when using the  (vowels in order)  input:     aeiou
────────────────────────────── 25104 words in the dictionary file:  unixdict.txt
          adventitious
          facetious
────────────────────────────── 2  "ABC" words found using the characters:  aeiou

Ring

cStr = read("unixdict.txt")
wordList = str2list(cStr)
num = 0

see "ABC words are:" + nl

for n = 1 to len(wordList)
    bool1 = substr(wordList[n],"a")
    bool2 = substr(wordList[n],"b")
    bool3 = substr(wordList[n],"c")
    bool4 = bool1 > 0 and bool2 > 0 and bool3 > 0
    bool5 = bool2 > bool1 and bool3 > bool2
    if bool4 = 1 and bool5 = 1
       num = num + 1
       see "" + num + ". " + wordList[n] + nl
    ok
next

Output:

ABC words are:
1. aback
2. abacus
3. abc
4. abdicate
5. abduct
6. abeyance
7. abject
8. abreact
9. abscess
10. abscissa
11. abscissae
12. absence
13. abstract
14. abstracter
15. abstractor
16. adiabatic
17. aerobacter
18. aerobic
19. albacore
20. alberich
21. albrecht
22. algebraic
23. alphabetic
24. ambiance
25. ambuscade
26. aminobenzoic
27. anaerobic
28. arabic
29. athabascan
30. auerbach
31. diabetic
32. diabolic
33. drawback
34. fabric
35. fabricate
36. flashback
37. halfback
38. iambic
39. lampblack
40. leatherback
41. metabolic
42. nabisco
43. paperback
44. parabolic
45. playback
46. prefabricate
47. quarterback
48. razorback
49. roadblock
50. sabbatical
51. snapback
52. strabismic
53. syllabic
54. tabernacle
55. tablecloth

RPL

The only way in RPL to use unixdict.txt as input is to download it locally and to convert it into a list of 25,104 strings, stored in the UnixDict global variable. Fortunately, emulators can handle such a big data structure in RAM.

Works with: RPL version HP-49C
« { } "abc"
  IF UnixDict OVER POS THEN + ELSE DROP END  
  @ speed up execution by reducing testing to words with 4+ characters
  1 UnixDict SIZE FOR j 
     'UnixDict' j GET
     CASE 
        DUP SIZE 4 <              THEN DROP END 
        DUP DUP2 3 →LIST { "a" "b" "c" } 2 « POS » DOLIST 
        DUP 1 GET NOT             THEN DROP2 END 
        2 « < » DOSUBS EVAL * NOT THEN DROP END 
        +
     END
  NEXT
» 'TASK' STO

Ruby

translation from Perl

puts File.open("unixdict.txt").grep(/^[^bc]*a[^c]*b.*c/)
Output:

Same 55 words

aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
...
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Rust

use std::fs;

fn isabcword(word: &&str) -> bool {
    let positions = ['a', 'b', 'c']
        .iter()
        .filter_map(|c| word.find(*c))
        .collect::<Vec<usize>>();
    return positions.len() == 3 && positions.windows(2).all(|w| w[0] <= w[1]);
}

fn main() {
    let wordsfile = fs::read_to_string("unixdict.txt").unwrap().to_lowercase();
    let words = wordsfile.split_whitespace().filter(|w| isabcword(w));
    for (i, w) in words.enumerate() {
        print!("{:<14}{}", w, if (i + 1) % 6 == 0 { "\n" } else { "" });
    }
    return ();
}
Output:
aback         abacus        abc           abdicate      abduct        abeyance      
abject        abreact       abscess       abscissa      abscissae     absence       
abstract      abstracter    abstractor    adiabatic     aerobacter    aerobic       
albacore      alberich      albrecht      algebraic     alphabetic    ambiance      
ambuscade     aminobenzoic  anaerobic     arabic        athabascan    auerbach      
diabetic      diabolic      drawback      fabric        fabricate     flashback     
halfback      iambic        lampblack     leatherback   metabolic     nabisco       
paperback     parabolic     playback      prefabricate  quarterback   razorback     
roadblock     sabbatical    snapback      strabismic    syllabic      tabernacle    
tablecloth

sed

$ sed '/^[^abc]*a[^bc]*b[^c]*c/!d' unixdict.txt   
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Swift

import Foundation

func loadDictionary(_ path: String) throws -> [String] {
    let contents = try String(contentsOfFile: path, encoding: String.Encoding.ascii)
    return contents.components(separatedBy: "\n")
}

func isAbcWord(_ word: String) -> Bool {
    var a = false
    var b = false
    for ch in word {
        switch (ch) {
        case "a":
            if !a {
                a = true
            }
        case "b":
            if !b {
                if !a {
                    return false
                }
                b = true
            }
        case "c":
            return b
        default:
            break
        }
    }
    return false
}

do {
    let dictionary = try loadDictionary("unixdict.txt")
    var n = 1
    for word in dictionary {
        if isAbcWord(word) {
            print("\(n): \(word)")
            n += 1
        }
    }
} catch {
    print(error)
}
Output:
1: aback
2: abacus
3: abc
4: abdicate
5: abduct
6: abeyance
7: abject
8: abreact
9: abscess
10: abscissa
11: abscissae
12: absence
13: abstract
14: abstracter
15: abstractor
16: adiabatic
17: aerobacter
18: aerobic
19: albacore
20: alberich
21: albrecht
22: algebraic
23: alphabetic
24: ambiance
25: ambuscade
26: aminobenzoic
27: anaerobic
28: arabic
29: athabascan
30: auerbach
31: diabetic
32: diabolic
33: drawback
34: fabric
35: fabricate
36: flashback
37: halfback
38: iambic
39: lampblack
40: leatherback
41: metabolic
42: nabisco
43: paperback
44: parabolic
45: playback
46: prefabricate
47: quarterback
48: razorback
49: roadblock
50: sabbatical
51: snapback
52: strabismic
53: syllabic
54: tabernacle
55: tablecloth

Tcl

proc is_abc_word word {
	regexp {^[^bc]*a[^c]*b.*c} $word
}

set res [lmap w [read [open unixdict.txt]] {
	if {[is_abc_word $w]} {set w} else continue
}]

puts "Found [llength $res] words:"
puts [join $res \n]
Output:
$ tclsh abc_words.tcl
Found 55 words:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth

Transd

#lang transd

MainModule : {
  _start: (lambda 
      (with fs FileStream() 
          (open-r fs "/mnt/tmp/unixdict.txt") )
          (for w in (read-lines fs) do
              (if (match w "^[^bc]*a[^c]*b.*c.*") (lout w))))
    )
}
Output:
aback
abacus
abc
... 55 words in total ...
syllabic
tabernacle
tablecloth

V (Vlang)

import os

fn main() {
    mut count := 1
    mut text :=''
    unixdict := os.read_file('./unixdict.txt') or {println('Error: file not found') exit(1)}
    for word in unixdict.split_into_lines() {
        if word.contains('a') 
        && word.index_any('a') < word.index_any('b') 
        && word.index_any('b') < word.index_any('c') {
            text += count++.str() + ': $word \n'
        }
    }
    println(text)
}
Output:
1: aback
2: abacus
3: abc
4: abdicate
5: abduct
6: abeyance
7: abject
8: abreact
9: abscess
10: abscissa
11: abscissae
12: absence
13: abstract
14: abstracter
15: abstractor
16: adiabatic
17: aerobacter
18: aerobic
19: albacore
20: alberich
21: albrecht
22: algebraic
23: alphabetic
24: ambiance
25: ambuscade
26: aminobenzoic
27: anaerobic
28: arabic
29: athabascan
30: auerbach
31: diabetic
32: diabolic
33: drawback
34: fabric
35: fabricate
36: flashback
37: halfback
38: iambic
39: lampblack
40: leatherback
41: metabolic
42: nabisco
43: paperback
44: parabolic
45: playback
46: prefabricate
47: quarterback
48: razorback
49: roadblock
50: sabbatical
51: snapback
52: strabismic
53: syllabic
54: tabernacle
55: tablecloth

Wren

Library: Wren-fmt
import "io" for File
import "./fmt" for Fmt

var wordList = "unixdict.txt" // local copy
var words = File.read(wordList).trimEnd().split("\n")
var count = 0
System.print("Based on first occurrences only, the ABC words in %(wordList) are:")
for (word in words) {
    var a = word.indexOf("a")
    var b = word.indexOf("b")
    var c = word.indexOf("c")
    if (a >= 0 && b > a && c > b) {
        count = count + 1
        Fmt.print("$2d: $s", count, word)
    }
}
Output:
Based on first occurrences only, the ABC words in unixdict.txt are:
 1: aback
 2: abacus
 3: abc
 4: abdicate
 5: abduct
 6: abeyance
 7: abject
 8: abreact
 9: abscess
10: abscissa
11: abscissae
12: absence
13: abstract
14: abstracter
15: abstractor
16: adiabatic
17: aerobacter
18: aerobic
19: albacore
20: alberich
21: albrecht
22: algebraic
23: alphabetic
24: ambiance
25: ambuscade
26: aminobenzoic
27: anaerobic
28: arabic
29: athabascan
30: auerbach
31: diabetic
32: diabolic
33: drawback
34: fabric
35: fabricate
36: flashback
37: halfback
38: iambic
39: lampblack
40: leatherback
41: metabolic
42: nabisco
43: paperback
44: parabolic
45: playback
46: prefabricate
47: quarterback
48: razorback
49: roadblock
50: sabbatical
51: snapback
52: strabismic
53: syllabic
54: tabernacle
55: tablecloth

XPL0

string  0;              \use zero-terminated strings
int     I, J, K, Ch, Len;
char    Word(100);      \(longest word in unixdict.txt is 22 chars)
def     LF=$0A, CR=$0D, EOF=$1A;
[FSet(FOpen("unixdict.txt", 0), ^I);    \open dictionary and set it to device 3
OpenI(3);
repeat  I:= 0;
        loop    [repeat Ch:= ChIn(3) until Ch # CR;     \remove possible CR
                if Ch=LF or Ch=EOF then quit;
                Word(I):= Ch;
                I:= I+1;
                ];
        Word(I):= 0;                    \terminate string
        Len:= I;
        for I:= 0 to Len-1 do
            if Word(I)=^a then
                [for J:= 0 to Len-1 do
                    if Word(J)=^b then
                        [for K:= 0 to Len-1 do
                            if Word(K)=^c then
                                [if K>J & J>I then
                                    [Text(0, Word);  CrLf(0)];
                                K:= Len;
                                ];
                        J:= Len;
                        ];
                I:= Len;
                ];
until   Ch = EOF;
]
Output:
aback
abacus
abc
abdicate
abduct
abeyance
abject
abreact
abscess
abscissa
abscissae
absence
abstract
abstracter
abstractor
adiabatic
aerobacter
aerobic
albacore
alberich
albrecht
algebraic
alphabetic
ambiance
ambuscade
aminobenzoic
anaerobic
arabic
athabascan
auerbach
diabetic
diabolic
drawback
fabric
fabricate
flashback
halfback
iambic
lampblack
leatherback
metabolic
nabisco
paperback
parabolic
playback
prefabricate
quarterback
razorback
roadblock
sabbatical
snapback
strabismic
syllabic
tabernacle
tablecloth