Abbreviations, simple

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

The use of   abbreviations   (also sometimes called synonyms, nicknames, AKAs, or aliases)   can be an
easy way to add flexibility when specifying or using commands, sub─commands, options, etc.


For this task, the following   command table   will be used:

   add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1


Notes concerning the above   command table:

  •   it can be thought of as one long literal string   (with blanks at end-of-lines)
  •   it may have superfluous blanks
  •   it may be in any case (lower/upper/mixed)
  •   the order of the words in the   command table   must be preserved as shown
  •   the user input(s) may be in any case (upper/lower/mixed)
  •   commands will be restricted to the Latin alphabet   (A ──► Z,   a ──► z)
  •   a command is followed by an optional number, which indicates the minimum abbreviation
  •   A valid abbreviation is a word that has:
  •   at least the minimum length of the word's minimum number in the command table
  •   compares equal (regardless of case) to the leading characters of the word in the command table
  •   a length not longer than the word in the command table
  •   ALT,   aLt,   ALTE,   and   ALTER   are all abbreviations of   ALTER 3
  •   AL,   ALF,   ALTERS,   TER,   and   A   aren't valid abbreviations of   ALTER 3
  •   The   3   indicates that any abbreviation for   ALTER   must be at least three characters
  •   Any word longer than five characters can't be an abbreviation for   ALTER
  •   o,   ov,   oVe,   over,   overL,   overla   are all acceptable abbreviations for   overlay 1
  •   if there isn't a number after the command,   then there isn't an abbreviation permitted


Task
  •   The command table needn't be verified/validated.
  •   Write a function to validate if the user "words"   (given as input)   are valid   (in the command table).
  •   If the word   is   valid,   then return the full uppercase version of that "word".
  •   If the word isn't valid,   then return the lowercase string:   *error*       (7 characters).
  •   A blank input   (or a null input)   should return a null string.
  •   Show all output here.


An example test case to be used for this task

For a user string of:

 riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin

the computer program should return the string:

 RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
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[edit]

Translation of: Python
V command_table_text =
|‘add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
  compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
  3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
  forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
  locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
  msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
  refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
  2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1’

V user_words = ‘riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin’

F find_abbreviations_length(command_table_text)
   ‘ find the minimal abbreviation length for each word.
        a word that does not have minimum abbreviation length specified
        gets it's full lengths as the minimum.
   ’
   [String = Int] command_table
   V input_list = command_table_text.split((‘ ’, "\n"), group_delimiters' 1B)
   V i = 0

   V word = ‘’
   L i < input_list.len | word != ‘’
      I word == ‘’
         word = input_list[i++]
      V abbr_len = I i < input_list.len {input_list[i++]} E String(word.len)
      X.try
         command_table[word] = Int(abbr_len)
         word = ‘’
      X.catch ValueError
         command_table[word] = word.len
         word = abbr_len
   R command_table

F find_abbreviations(command_table)
   ‘ for each command insert all possible abbreviations’
   [String = String] abbreviations
   L(command, min_abbr_len) command_table
      L(l) min_abbr_len .. command.len
         V abbr = command[0 .< l].lowercase()
         abbreviations[abbr] = command.uppercase()
   R abbreviations

F parse_user_string(user_string, abbreviations)
   V user_words = user_string.split(‘ ’, group_delimiters' 1B).map(word -> word.lowercase())
   V commands = user_words.map(user_word -> @abbreviations.get(user_word, ‘*error*’))
   R commands.join(‘ ’)

V command_table = find_abbreviations_length(command_table_text)
V abbreviations_table = find_abbreviations(command_table)

V full_words = parse_user_string(user_words, abbreviations_table)

print(‘user words: ’user_words)
print(‘full words: ’full_words)
Output:
user words: riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
full words: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

AArch64 Assembly[edit]

Works with: as version Raspberry Pi 3B version Buster 64 bits
/* ARM assembly AARCH64 Raspberry PI 3B */
/*  program abbrSimple64.s   */
/* store list of command in a file commandSimple.txt */
/* and run the program  abbrSimple64 commandSimple.txt */

/*******************************************/
/* Constantes file                         */
/*******************************************/
/* for this file see task include a file in language AArch64 assembly*/
.include "../includeConstantesARM64.inc"

.equ BUFFERSIZE,   1000
.equ NBMAXIELEMENTS, 100

/*******************************************/
/* Structures                               */
/********************************************/
/* command structure      */
    .struct  0
command_name_address:                   // name
    .struct  command_name_address + 8 
command_min:                            // minimum letters
    .struct  command_min + 8
command_end:
/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessTitre:            .asciz "Nom du fichier : "
szCarriageReturn:      .asciz "\n"
szMessErreur:          .asciz "Error detected.\n"
szMessErrBuffer:       .asciz "buffer size too less !!"
szMessCtrlCom:         .asciz "Command : @   minimum : @ \n"
szMessErrorAbr:        .asciz "*error*"
szMessInput:           .asciz "Enter command (or <ctrl-c> to stop) : "

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4
sZoneConv:      .skip 24
qAdrFicName:    .skip 8
iTabAdrCmd:     .skip command_end * NBMAXIELEMENTS 
sBufferCmd:     .skip BUFFERSIZE
sBuffer:        .skip BUFFERSIZE
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main 
main:                            // INFO: main
    mov x0,sp                    // stack address for load parameter
    bl traitFic                  // read file and store value in array
    cmp x0,#-1
    beq 100f                     // error ?
    ldr x0,qAdriTabAdrCmd
    bl controlLoad
    
1:
    ldr x0,qAdrszMessInput       // display input message
    bl affichageMess
    mov x0,#STDIN                // Linux input console
    ldr x1,qAdrsBuffer           // buffer address 
    mov x2,#BUFFERSIZE           // buffer size 
    mov x8, #READ                // request to read datas
    svc 0                        // call system
    sub x0,x0,#1
    mov x2,#0
    strb w2,[x1,x0]              // replace character 0xA by zéro final
    cbnz x0,2f                   // null string ?
    mov x0,x1
    b 3f
2:
    ldr x0,qAdrsBuffer   
    ldr x1,qAdriTabAdrCmd
    bl controlCommand            // control text command
3:
    mov x2,x0                    // display result
    bl affichageMess
    ldr x0,qAdrszCarriageReturn
    bl affichageMess
 
    b 1b                         // loop

99:
    ldr x0,qAdrszMessErrBuffer
    bl affichageMess
100:                                 // standard end of the program 
    mov x0, #0                       // return code
    mov x8, #EXIT                    // request to exit program
    svc #0                           // perform the system call
 
qAdrszCarriageReturn:      .quad szCarriageReturn
qAdrszMessErrBuffer:       .quad szMessErrBuffer
qAdrsZoneConv:             .quad sZoneConv
qAdrszMessInput:           .quad szMessInput
/******************************************************************/
/*      control abbrevation command                               */ 
/******************************************************************/
/* x0 contains string input command */
/* x1 contains address table string command */
controlCommand:                  // INFO: controlCommand
    stp x1,lr,[sp,-16]!          // save  registres
    stp x2,x3,[sp,-16]!          // save  registres
    stp x4,x5,[sp,-16]!          // save  registres
    stp x6,x7,[sp,-16]!          // save  registres
    stp x8,x9,[sp,-16]!          // save  registres
    mov x8,x0
    mov x9,x1
    mov x10,#command_end          // length item
    bl computeLength              // length input command
    mov x4,x0                     // save length input
    mov x2,#0                     // indice
    mov x3,#0                     // find counter
1:
    mov x0,x8
    madd x6,x2,x10,x9              // compute address
    ldr x1,[x6,#command_name_address]  // load a item
    cbz x1,5f                     // end ?
    bl comparStringSpe            // 
    cbz x0,4f                     // no found other search
    ldr x5,[x6,#command_min]
    cmp x5,#0                     // minimum = zéro ?
    ble 2f
    cmp x4,x5                     // input < command capital letters
    blt 4f                        // no correct
    
    add x3,x3,#1                  // else increment counter
    mov x7,x1                     // and save address command
    b 4f
2:
    mov x0,x1
    bl computeLength              // length table command
    cmp x0,x4                     // length input commant <> lenght table command
    bne 4f                        // no correct
    add x3,x3,#1                  // else increment counter
    mov x7,x1                     // and save address command
4:
    add x2,x2,#1                  // increment indice
    b 1b                          // and loop
5:
    cmp x3,#1                     // no find or multiple find ?
    bne 99f                       // error 
                                  // one find
    mov x0,x7                     // length command table
    bl computeLength
    cmp x4,x0                     // length input > command ?
    bgt 99f                       // error

    mov x4,#0x20                  // 5 bit to 1
    mov x2,#0
6:
    ldrb w3,[x7,x2]
    cbz w3,7f
    bic x3,x3,x4                  // convert to capital letter
    strb w3,[x8,x2]
    add x2,x2,#1
    b 6b
7:
    strb w3,[x8,x2]
    mov x0,x8                     // return string input address
    b 100f
99:
    ldr x0,qAdrszMessErrorAbr     // return string "error"
100:
    ldp x8,x9,[sp],16             // restaur des  2 registres
    ldp x6,x7,[sp],16             // restaur des  2 registres
    ldp x4,x5,[sp],16             // restaur des  2 registres
    ldp x2,x3,[sp],16             // restaur des  2 registres
    ldp x1,lr,[sp],16             // restaur des  2 registres
    ret
qAdrszMessErreur:           .quad szMessErreur
qAdrszMessErrorAbr:         .quad szMessErrorAbr
/******************************************************************/
/*     comparaison first letters String                                          */ 
/******************************************************************/
/* x0 contains first String   */
/* x1 contains second string */
/* x0 return 0 if not find else returns number letters OK */
comparStringSpe:
    stp x1,lr,[sp,-16]!          // save  registres
    stp x2,x3,[sp,-16]!          // save  registres
    stp x4,x5,[sp,-16]!          // save  registres
    stp x6,x7,[sp,-16]!          // save  registres
    mov x2,#0
1:
    ldrb w3,[x0,x2]           // input
    orr w4,w3,#0x20           // convert capital letter
    ldrb w5,[x1,x2]           // table
    orr w6,w5,#0x20           // convert capital letter
    cmp w4,w6
    bne 2f
    cbz w3,3f                 // end strings ?
    add x2,x2,#1
    b 1b 
2:
   cbz w3,3f                  // fist letters Ok
   mov x0,#0                  // no ok
   b 100f
3:
   mov x0,x2
100:
    ldp x6,x7,[sp],16           // restaur des  2 registres
    ldp x4,x5,[sp],16           // restaur des  2 registres
    ldp x2,x3,[sp],16           // restaur des  2 registres
    ldp x1,lr,[sp],16           // restaur des  2 registres
    ret
/******************************************************************/
/*     compute length  String                                          */ 
/******************************************************************/
/* x0 contains  String   */
/* x0 return length */ 
computeLength:                   // INFO: functionFN
    stp x1,lr,[sp,-16]!          // save  registres
    stp x2,x3,[sp,-16]!          // save  registres
    mov x1,#0
1:
    ldrb w2,[x0,x1]
    cbz w2,2f                    // end ?
    add x1,x1,#1
    b 1b
2:
    mov x0,x1                  // return length in x0
100:
    ldp x2,x3,[sp],16           // restaur des  2 registres
    ldp x1,lr,[sp],16           // restaur des  2 registres
    ret
/******************************************************************/
/*     read file                                                   */ 
/******************************************************************/
/* x0 contains address stack begin           */
traitFic:                             // INFO: traitFic
    stp x1,lr,[sp,-16]!          // save  registres
    stp x2,x3,[sp,-16]!          // save  registres
    stp x4,x5,[sp,-16]!          // save  registres
    stp x6,x7,[sp,-16]!          // save  registres
    stp x8,fp,[sp,-16]!          // save  registres
    mov fp,x0                         //  fp <- start address
    ldr x4,[fp]                       // number of Command line arguments
    cmp x4,#1
    ble 99f
    add x5,fp,#16                      // second parameter address 
    ldr x5,[x5]
    ldr x0,qAdrqAdrFicName
    str x5,[x0]
    ldr x0,qAdrszMessTitre
    bl affichageMess                  // display string
    mov x0,x5
    bl affichageMess 
    ldr x0,qAdrszCarriageReturn
    bl affichageMess                  // display carriage return

    mov x0,AT_FDCWD
    mov x1,x5                         // file name
    mov x2,#O_RDWR                    // flags    
    mov x3,#0                         // mode 
    mov x8, #OPEN                     // call system OPEN 
    svc 0 
    cmp x0,#0                         // error ?
    ble 99f
    mov x7,x0                         // File Descriptor
    ldr x1,qAdrsBufferCmd             // buffer address
    mov x2,#BUFFERSIZE                // buffer size
    mov x8,#READ                      // read file
    svc #0
    cmp x0,#0                         // error ?
    blt 99f
    // extraction datas
    ldr x1,qAdrsBufferCmd             // buffer address
    add x1,x1,x0
    mov x0,#0                         // store zéro final
    strb w0,[x1] 
    ldr x0,qAdriTabAdrCmd             // key string command table
    ldr x1,qAdrsBufferCmd             // buffer address
    bl extracDatas
                                      // close file
    mov x0,x7
    mov x8, #CLOSE 
    svc 0 
    mov x0,#0
    b 100f
99:                                   // error
    ldr x0,qAdrszMessErreur           // error message
    bl   affichageMess
    mov x0,#-1
100:
    ldp x8,fp,[sp],16           // restaur des  2 registres
    ldp x6,x7,[sp],16           // restaur des  2 registres
    ldp x4,x5,[sp],16           // restaur des  2 registres
    ldp x2,x3,[sp],16           // restaur des  2 registres
    ldp x1,lr,[sp],16           // restaur des  2 registres
    ret
qAdrqAdrFicName:              .quad qAdrFicName
qAdrszMessTitre:              .quad szMessTitre
qAdrsBuffer:                  .quad sBuffer
qAdrsBufferCmd:               .quad sBufferCmd
qAdriTabAdrCmd:               .quad iTabAdrCmd
/******************************************************************/
/*     extrac digit file buffer                                   */ 
/******************************************************************/
/* x0 contains strings address           */
/* x1 contains buffer address         */
extracDatas:                     // INFO: extracDatas
    stp x1,lr,[sp,-16]!          // save  registres
    stp x2,x3,[sp,-16]!          // save  registres
    stp x4,x5,[sp,-16]!          // save  registres
    stp x6,x7,[sp,-16]!          // save  registres
    stp x8,fp,[sp,-16]!          // save  registres
    mov x7,x0
    mov x6,x1
    mov x8,#0                    // top command name
    mov x2,#0                    // string buffer indice
    mov x4,x1                    // start string
    mov x5,#0                    // string index
1:
    ldrb w3,[x6,x2]
    cbz w3,4f                    // end
    cmp x3,#0xA
    beq 2f
    cmp x3,#' '                  // end string
    beq 3f
    add x2,x2,#1
    b 1b
2:
    mov x3,#0
    strb w3,[x6,x2]
    ldrb w3,[x6,x2]
    cmp w3,#0xD
    bne 21f
    add x2,x2,#2
    b 4f
21:
    add x2,x2,#1
    b 4f
 
3:
    mov x3,#0
    strb w3,[x6,x2]
    add x2,x2,#1
4:  
    mov x0,x4
    ldrb w1,[x0]                // load first byte
    cmp w1,#'0'                 // it is à digit ?
    blt 5f
    cmp w1,#'9'
    bgt 5f
    mov x1,#command_end
    madd x1,x5,x1,x7              // compute address to store
    mov x0,x4
    bl conversionAtoD            // conversion ascii digit
    str x0,[x1,#command_min]     // and store in minimum
    mov x8,#0                    // line command ok
    add x5,x5,#1                    // increment indice
    b 7f
5:
    cmp x8,#0                    // other name ?
    beq 6f
    mov x0,#0                    // yes store zéro in minimum in prec 
    mov x1,#command_end
    madd x1,x5,x1,x7
    add x1,x1,#command_min
    str x0,[x1]
    add x5,x5,#1                    // and increment indice
6:
    mov x8,#1                    // load name
    mov x1,#command_end
    madd x1,x5,x1,x7              // store name in table
    str x4,[x1,#command_name_address]
7:                               // loop suppress spaces
    ldrb w3,[x6,x2]
    cmp w3,#0
    beq 100f
    cmp w3,#' '
    cinc x2,x2,eq
    beq 7b
    
    add x4,x6,x2                 // new start address
    b 1b
100:
    ldp x8,fp,[sp],16           // restaur des  2 registres
    ldp x6,x7,[sp],16           // restaur des  2 registres
    ldp x4,x5,[sp],16           // restaur des  2 registres
    ldp x2,x3,[sp],16           // restaur des  2 registres
    ldp x1,lr,[sp],16           // restaur des  2 registres
    ret
/******************************************************************/
/*     control load                                      */ 
/******************************************************************/
/* x0 contains string table           */
controlLoad:
    stp x1,lr,[sp,-16]!          // save  registres
    stp x2,x3,[sp,-16]!          // save  registres
    stp x4,x5,[sp,-16]!          // save  registres
    stp x6,x7,[sp,-16]!          // save  registres
    mov x5,x0
    mov x6,#0
    mov x2,#command_end
1:
    madd x3,x6,x2,x5             // compute item address 
    ldr x1,[x3,#command_name_address]
    cbz x1,100f
    ldr x0,qAdrszMessCtrlCom
    bl strInsertAtCharInc
    mov x4,x0
    ldr x0,[x3,#command_min]
    ldr x1,qAdrsZoneConv
    bl conversion10              // call decimal conversion
    mov x0,x4
    ldr x1,qAdrsZoneConv         // insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess             // display message
    add x6,x6,#1
    b 1b
    
100:
    ldp x6,x7,[sp],16           // restaur des  2 registres
    ldp x4,x5,[sp],16           // restaur des  2 registres
    ldp x2,x3,[sp],16           // restaur des  2 registres
    ldp x1,lr,[sp],16           // restaur des  2 registres
    ret
qAdrszMessCtrlCom:       .quad szMessCtrlCom

/********************************************************/
/*        File Include fonctions                        */
/********************************************************/
/* for this file see task include a file in language AArch64 assembly */
.include "../includeARM64.inc"
Enter command (or <ctrl-c> to stop) : riG
RIGHT
Enter command (or <ctrl-c> to stop) : rePEAT
REPEAT
Enter command (or <ctrl-c> to stop) : copies
*error*
Enter command (or <ctrl-c> to stop) : put
PUT
Enter command (or <ctrl-c> to stop) : mo
MOVE
Enter command (or <ctrl-c> to stop) : rest
RESTORE
Enter command (or <ctrl-c> to stop) : types
*error*
Enter command (or <ctrl-c> to stop) : fup.
*error*
Enter command (or <ctrl-c> to stop) : 6
*error*
Enter command (or <ctrl-c> to stop) : poweRin
POWERINPUT
Enter command (or <ctrl-c> to stop) : ^C
pi@debian-buster-64:~/asm64/rosetta/asm9 $

Ada[edit]

with Ada.Characters.Handling;
with Ada.Containers.Vectors;
with Ada.Strings.Fixed;
with Ada.Strings.Maps.Constants;
with Ada.Strings.Unbounded;
with Ada.Text_IO;

procedure Abbreviations_Simple is

   use Ada.Strings.Unbounded;
   subtype Ustring is Unbounded_String;

   type Word_Entry is record
      Word : Ustring;
      Min  : Natural;
   end record;

   package Command_Vectors
   is new Ada.Containers.Vectors (Index_Type   => Positive,
                                  Element_Type => Word_Entry);

   Commands      : Command_Vectors.Vector;
   Last_Word     : Ustring;
   Last_Was_Word : Boolean := False;

   procedure Append (Word_List : String) is
      use Ada.Strings;

      function Is_Word (Item : String) return Boolean
      is (Fixed.Count (Item, Maps.Constants.Letter_Set) /= 0);

      procedure Process (Token : String) is
      begin
         if Is_Word (Token) then
            if Last_Was_Word then
               Commands.Append ((Word => Last_Word,
                                 Min  => Length (Last_Word)));
            end if;
            Last_Word     := To_Unbounded_String (Token);
            Last_Was_Word := True;

         else  -- Token is expected to be decimal
            Commands.Append ((Word => Last_Word,
                              Min  => Natural'Value (Token)));
            Last_Was_Word := False;
         end if;
      end Process;

      Token_First : Positive := Word_List'First;
      Token_Last  : Natural;
   begin
      while Token_First in Word_List'Range loop

         Fixed.Find_Token (Word_List, Maps.Constants.Alphanumeric_Set,
                           Token_First, Inside,
                           Token_First, Token_Last);
         exit when Token_Last = 0;

         Process (Word_List (Token_First .. Token_Last));

         Token_First := Token_Last + 1;
      end loop;
   end Append;

   function Match (Word : String) return String is
      use Ada.Characters.Handling;
      use Ada.Strings.Fixed;
      Result : Ustring := To_Unbounded_String ("*error*");
      Min    : Natural := 0;
      Upper_Word : constant String := To_Upper (Word);
   begin
      if Upper_Word = "" then
         return "";
      end if;

      for Candidate of Commands loop
         declare
            Upper_Cand : constant String  := To_Upper (To_String (Candidate.Word));
            Length     : constant Natural := Natural'Max (Candidate.Min,
                                                          Upper_Word'Length);
            Upper_Abbrev_Cand : constant String := Head (Upper_Cand, Length);
            Upper_Abbrev_Word : constant String := Head (Upper_Word, Length);
         begin
            if Upper_Word = Upper_Cand
              and then Upper_Word'Length > Min
            then
               Result := To_Unbounded_String (Upper_Cand);
               Min    := Upper_Word'Length;
            elsif Upper_Abbrev_Word = Upper_Abbrev_Cand
              and then Upper_Abbrev_Word'Length > Min
            then
               Result := To_Unbounded_String (Upper_Cand);
               Min    := Upper_Abbrev_Word'Length;
            end if;
         end;
      end loop;
      return To_String (Result);
   end Match;

   procedure Put_Match (To : String) is
      use Ada.Text_IO;
   begin
      Put ("Match to '");  Put (To);
      Put ("' is '");      Put (Match (To));
      Put_Line ("'");
   end Put_Match;

   procedure A (Item : String) renames Append;
begin
   A ("add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3");
   A ("compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate");
   A ("3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2");
   A ("forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load");
   A ("locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2");
   A ("msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3");
   A ("refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left");
   A ("2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1");

   Put_Match ("riG");
   Put_Match ("rePEAT");
   Put_Match ("copies");
   Put_Match ("put");
   Put_Match ("mo");
   Put_Match ("rest");
   Put_Match ("types");
   Put_Match ("fup.");
   Put_Match ("6");
   Put_Match ("poweRin");
   Put_Match ("");
end Abbreviations_Simple;
Output:
Match to 'riG' is 'RIGHT'
Match to 'rePEAT' is 'REPEAT'
Match to 'copies' is '*error*'
Match to 'put' is 'PUT'
Match to 'mo' is 'MOVE'
Match to 'rest' is 'RESTORE'
Match to 'types' is '*error*'
Match to 'fup.' is '*error*'
Match to '6' is '*error*'
Match to 'poweRin' is 'POWERINPUT'
Match to '' is ''

ALGOL 68[edit]

Works with: ALGOL 68G version Any - tested with release 2.8.3.win32
# "Simple" abbreviations                                               #

# returns the next word from text, updating pos                        #
PRIO NEXTWORD = 1;
OP   NEXTWORD = ( REF INT pos, STRING text )STRING:
     BEGIN
        # skip spaces #
        WHILE IF pos > UPB text THEN FALSE ELSE text[ pos ] = " " FI DO pos +:= 1 OD;
        # get the word #
        STRING word := "";
        WHILE IF pos > UPB text THEN FALSE ELSE text[ pos ] /= " " FI DO
            word +:= text[ pos ];
            pos +:= 1
        OD;
        word
     END # NEXTWORD # ;
# returns text converted to upper case                                 #
OP   TOUPPER  = ( STRING text )STRING:
     BEGIN
        STRING result := text;
        FOR ch pos FROM LWB result TO UPB result DO
            IF is lower( result[ ch pos ] ) THEN result[ ch pos ] := to upper( result[ ch pos ] ) FI
        OD;
        result
     END # TOUPPER # ;
# returns text converted to an INT or -1 if text is not a number         #
OP   TOINT    = ( STRING text )INT:
     BEGIN
        INT  result     := 0;
        BOOL is numeric := TRUE;
        FOR ch pos FROM UPB text BY -1 TO LWB text WHILE is numeric DO
            CHAR c = text[ ch pos ];
            is numeric := ( c >= "0" AND c <= "9" );
            IF is numeric THEN ( result *:= 10 ) +:= ABS c - ABS "0" FI        
        OD;
        IF is numeric THEN result ELSE -1 FI
     END # TOINT # ;
# returns the length of word                                             #
OP LENGTH = ( STRING word )INT: 1 + ( UPB word - LWB word );
# counts the number of commands in commands                              #
PROC count commands = ( STRING commands )INT:
     BEGIN
        INT    result         := 0;
        INT    pos            := LWB commands;
        WHILE  STRING command := pos NEXTWORD commands; command /= "" DO
            IF TOINT command < 0 THEN
                # not an abbreviation length                             #
                result +:= 1
            FI
        OD;
        result
     END # count commands # ;

# list of "commands" -  the words are optionally followed by the minimum #
#                       length of abbreviation - if there isn't a number #
#                       the command can only appear in full              #
STRING commands
   = "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 "
   + "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate "
   + "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 "
   + "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load "
   + "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 "
   + "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 "
   + "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left "
   + "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1 "
   ;
# build the tables of the commands and their minimum lengths             #
PROC load commands = ( STRING commands )VOID:
     BEGIN
        INT    cmd pos        := 0;
        INT    pos            := LWB command table;
        WHILE  STRING command := pos NEXTWORD commands; command /= "" DO
            INT len := TOINT command;
            IF len >= 0 THEN
                # have an abbreviation length                            #
                IF cmd pos > 0 THEN min abbreviation[ cmd pos ] := len FI
            ELSE
                # new command                                            #
                cmd pos +:= 1;
                command table[    cmd pos ] := TOUPPER command;
                min abbreviation[ cmd pos ] := LENGTH  command
            FI
        OD
     END # load commands # ;
# searches for word in command table and returns the full command      #
# matching the possible abbreviation or *error* if there is no match   #
OP   EXPAND  = ( STRING word )STRING:
     IF word = ""
     THEN # empty word #
        ""
     ELSE # non-empty word #
        INT    word len    = LENGTH word;
        STRING upper word := TOUPPER word;
        STRING result     := "*error*";
        FOR cmd pos FROM LWB command table TO UPB command table
        WHILE  STRING command := command table[ cmd pos ];
               IF word len < min abbreviation[ cmd pos ] OR word len > LENGTH command
               THEN # word is too short or too long - try the next command #
                   TRUE
               ELIF upper word = command[ LWB command : ( LWB command - 1 ) + word len ]
               THEN # found the command #
                   result := command;
                   FALSE
               ELSE # word doexn't match - try the next command #
                   TRUE
               FI
        DO SKIP OD;
        result
     FI # EXPAND # ;

# tests the EXPAND operator                                            #
PROC test expand = ( STRING words )VOID:
     BEGIN
        STRING results := "", separator := "";
        INT    pos   := LWB words;
        WHILE STRING word = pos NEXTWORD words; word /= "" DO
            results +:= separator + EXPAND word;
            separator := " "
        OD;
        print( ( "Input:  ", words, newline ) );
        print( ( "Output: ", results, newline ) )
     END # test expand # ;

# build the command table                                              #
[ 1 : count commands( commands ) ]STRING command table;
[ 1 : UPB command table          ]INT    min abbreviation;
load commands( commands );

# task test cases                                                      #
test expand( "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin" )
Output:
Input:  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
Output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

ARM Assembly[edit]

This example is in need of improvement:


Please include the required/mandatory test cases mentioned in the task's requirements:

riG   rePEAT   copies   put   mo   rest   types   fup.   6   poweRin

Note that the test cases are in mixed case.

Also note that   put   isn't an error.
 Ok correction le 17/11/2020 16H 
Works with: as version Raspberry Pi
/* ARM assembly Raspberry PI  */
/*  program abbrSimple.s   */
/* store list of command in a file */
/* and run the program  abbrSimple command.file */

/* REMARK 1 : this program use routines in a include file 
   see task Include a file language arm assembly 
   for the routine affichageMess conversion10 
   see at end of this program the instruction include */
/* for constantes see task include a file in arm assembly */
/************************************/
/* Constantes                       */
/************************************/
.include "../constantes.inc"

.equ STDIN,  0     @ Linux input console
.equ STDOUT, 1     @ Linux output console
.equ EXIT,   1     @ Linux syscall
.equ READ,   3     @ Linux syscall
.equ WRITE,  4     @ Linux syscall
.equ OPEN,   5     @ Linux syscall
.equ CLOSE,  6     @ Linux syscall

.equ O_RDWR,    0x0002        @ open for reading and writing

.equ BUFFERSIZE,   1000
.equ NBMAXIELEMENTS, 100

/*******************************************/
/* Structures                               */
/********************************************/
/* command structure      */
    .struct  0
command_name_address:                   @ name
    .struct  command_name_address + 4 
command_min:                            @ minimum letters
    .struct  command_min + 4
command_end:
/*********************************/
/* Initialized data              */
/*********************************/
.data
szMessTitre:            .asciz "Nom du fichier : "
szCarriageReturn:      .asciz "\n"
szMessErreur:          .asciz "Error detected.\n"
szMessErrBuffer:       .asciz "buffer size too less !!"
szMessCtrlCom:         .asciz "Command : @   minimum : @ \n"
szMessErrorAbr:        .asciz "*error*"
szMessInput:           .asciz "Enter command (or <ctrl-c> to stop) : "

/*********************************/
/* UnInitialized data            */
/*********************************/
.bss
.align 4
sZoneConv:      .skip 24
iAdrFicName:    .skip 4
iTabAdrCmd:     .skip command_end * NBMAXIELEMENTS 
sBufferCmd:     .skip BUFFERSIZE
sBuffer:        .skip BUFFERSIZE
/*********************************/
/*  code section                 */
/*********************************/
.text
.global main 
main:                            @ INFO: main
    mov r0,sp                    @ stack address for load parameter
    bl traitFic                  @ read file and store value in array
    cmp r0,#-1
    beq 100f                     @ error ?
    ldr r0,iAdriTabAdrCmd
    bl controlLoad
    
1:
    ldr r0,iAdrszMessInput       @ display input message
    bl affichageMess
    mov r0,#STDIN                @ Linux input console
    ldr r1,iAdrsBuffer           @ buffer address 
    mov r2,#BUFFERSIZE           @ buffer size 
    mov r7, #READ                @ request to read datas
    svc 0                        @ call system
    sub r0,r0,#1
    mov r2,#0
    strb r2,[r1,r0]              @ replace character 0xA by zéro final
    cmp r0,#0                    @ null string ?
    moveq r0,r1
    beq 2f
    ldr r0,iAdrsBuffer   
    ldr r1,iAdriTabAdrCmd
    bl controlCommand            @ control text command
2:
    mov r2,r0                    @ display result
    bl affichageMess
    ldr r0,iAdrszCarriageReturn
    bl affichageMess
 
    b 1b                         @ loop

99:
    ldr r0,iAdrszMessErrBuffer
    bl affichageMess
100:                                 @ standard end of the program 
    mov r0, #0                       @ return code
    mov r7, #EXIT                    @ request to exit program
    svc #0                           @ perform the system call
 
iAdrszCarriageReturn:      .int szCarriageReturn
iAdrszMessErrBuffer:       .int szMessErrBuffer
iAdrsZoneConv:             .int sZoneConv
iAdrszMessInput:           .int szMessInput
/******************************************************************/
/*      control abbrevation command                               */ 
/******************************************************************/
/* r0 contains string input command */
/* r1 contains address table string command */
controlCommand:                   @ INFO: controlCommand
    push {r1-r8,lr}               @ save  registers
    mov r8,r0
    mov r9,r1
    mov r10,#command_end          @ length item
    bl computeLength              @ length input command
    mov r4,r0                     @ save length input
    mov r2,#0                     @ indice
    mov r3,#0                     @ find counter
1:
    mov r0,r8
    mla r6,r2,r10,r9              @ compute address
    ldr r1,[r6,#command_name_address]         @ load a item
    cmp r1,#0                     @ end ?
    beq 5f
    bl comparStringSpe            @ 
    cmp r0,#0                     @ no found other search
    beq 4f
    ldr r5,[r6,#command_min]
    cmp r5,#0                     @ minimum = zéro ?
    ble 2f
    cmp r4,r5                     @ input < command minimum letters
    blt 4f                        @ no correct
    
    add r3,r3,#1                  @ else increment counter
    mov r7,r1                     @ and save address command
    b 4f
2:
    mov r0,r1
    bl computeLength              @ length input command
    cmp r4,r0                     @ length command input = length command
    bne 4f                        @ no correct
    add r3,r3,#1                  @ else increment counter
    mov r7,r1                     @ and save address command
4:
    add r2,r2,#1                  @ increment indice
    b 1b                          @ and loop
5:
    cmp r3,#1                     @ no find or multiple find ?
    bne 99f                       @ error 
                                  @ one find
    mov r0,r7                     @ length command table
    bl computeLength
    cmp r4,r0                     @ length input > command ?
    bgt 99f                       @ error

    mov r4,#0x20                  @ 5 bit to 1
    mov r2,#0
6:
    ldrb r3,[r7,r2]
    cmp r3,#0
    beq 7f
    bic r3,r3,r4                  @ convert to capital letter
    strb r3,[r8,r2]
    add r2,r2,#1
    b 6b
7:
    strb r3,[r8,r2]
    mov r0,r8                     @ return string input address
    b 100f
99:
    ldr r0,iAdrszMessErrorAbr     @ return string "error"
100:
    pop {r1-r8,lr}                @ restaur registers 
    bx lr                         @return
iAdrszMessErreur:           .int szMessErreur
iAdrszMessErrorAbr:         .int szMessErrorAbr
/******************************************************************/
/*     comparaison first letters String                                          */ 
/******************************************************************/
/* r0 contains first String   */
/* r1 contains second string */
/* r0 return 0 if not find else returns number letters OK */
comparStringSpe:
    push {r1-r6,lr}           @ save  register
    mov r2,#0
1:
    ldrb r3,[r0,r2]           @ input
    orr r4,r3,#0x20           @ convert capital letter
    ldrb r5,[r1,r2]           @ table
    orr r6,r5,#0x20           @ convert capital letter
    cmp r4,r6
    bne 2f
    cmp r3,#0
    beq 3f
    add r2,r2,#1
    b 1b 
2:
   cmp r3,#0                  @ fist letters Ok
   beq 3f
   mov r0,#0                  @ no ok
   b 100f
3:
   mov r0,r2
100:
    pop {r1-r6,lr}                     @ restaur registers 
    bx lr                        @return
/******************************************************************/
/*     compute length  String                                          */ 
/******************************************************************/
/* r0 contains  String   */
/* r0 return length */ 
computeLength:                   @ INFO: functionFN
    push {r1-r2,lr}              @ save  register
    mov r1,#0
1:
    ldrb r2,[r0,r1]
    cmp r2,#0                    @ end ?
    moveq r0,r1                  @ return length in r0
    beq 100f
    add r1,r1,#1
    b 1b
100:
    pop {r1-r2,lr}               @ restaur registers 
    bx lr                        @return 

/******************************************************************/
/*     read file                                                   */ 
/******************************************************************/
/* r0 contains address stack begin           */
traitFic:                             @ INFO: traitFic
    push {r1-r8,fp,lr}                @ save  registers
    mov fp,r0                         @  fp <- start address
    ldr r4,[fp]                       @ number of Command line arguments
    cmp r4,#1
    movle r0,#-1
    ble 99f
    add r5,fp,#8                      @ second parameter address 
    ldr r5,[r5]
    ldr r0,iAdriAdrFicName
    str r5,[r0]
    ldr r0,iAdrszMessTitre
    bl affichageMess                  @ display string
    mov r0,r5
    bl affichageMess 
    ldr r0,iAdrszCarriageReturn
    bl affichageMess                  @ display carriage return

    mov r0,r5                         @ file name
    mov r1,#O_RDWR                    @ flags    
    mov r2,#0                         @ mode 
    mov r7, #OPEN                     @ call system OPEN 
    svc 0 
    cmp r0,#0                         @ error ?
    ble 99f
    mov r8,r0                         @ File Descriptor
    ldr r1,iAdrsBufferCmd             @ buffer address
    mov r2,#BUFFERSIZE                @ buffer size
    mov r7,#READ                      @ read file
    svc #0
    cmp r0,#0                         @ error ?
    blt 99f
    @ extraction datas
    ldr r1,iAdrsBufferCmd             @ buffer address
    add r1,r0
    mov r0,#0                         @ store zéro final
    strb r0,[r1] 
    ldr r0,iAdriTabAdrCmd             @ key string command table
    ldr r1,iAdrsBufferCmd             @ buffer address
    bl extracDatas
                                      @ close file
    mov r0,r8
    mov r7, #CLOSE 
    svc 0 
    mov r0,#0
    b 100f
99:                                   @ error
    ldr r1,iAdrszMessErreur           @ error message
    bl   displayError
    mov r0,#-1
100:
    pop {r1-r8,fp,lr}                 @ restaur registers 
    bx lr                             @return
iAdriAdrFicName:              .int iAdrFicName
iAdrszMessTitre:              .int szMessTitre
iAdrsBuffer:                  .int sBuffer
iAdrsBufferCmd:               .int sBufferCmd
iAdriTabAdrCmd:               .int iTabAdrCmd
/******************************************************************/
/*     extrac digit file buffer                                   */ 
/******************************************************************/
/* r0 contains strings address           */
/* r1 contains buffer address         */
extracDatas:                     @ INFO: extracDatas
    push {r1-r8,lr}              @ save  registers
    mov r7,r0
    mov r6,r1
    mov r8,#0                    @ top command name
    mov r2,#0                    @ string buffer indice
    mov r4,r1                    @ start string
    mov r5,#0                    @ string index
1:
    ldrb r3,[r6,r2]
    cmp r3,#0
    beq 4f                       @ end
    cmp r3,#0xA
    beq 2f
    cmp r3,#' '                  @ end string
    beq 3f
    add r2,#1
    b 1b
2:
    mov r3,#0
    strb r3,[r6,r2]
    ldrb r3,[r6,r2]
    cmp r3,#0xD
    addeq r2,#2
    addne r2,#1
    b 4f
 
3:
    mov r3,#0
    strb r3,[r6,r2]
    add r2,#1
4:  
    mov r0,r4
    ldrb r1,[r0]                @ load first byte
    cmp r1,#'0'                 @ it is à digit ?
    blt 5f
    cmp r1,#'9'
    bgt 5f
    mov r0,r1  
    mov r1,#command_end
    mla r1,r5,r1,r7              @ compute address to store
    mov r0,r4
    bl conversionAtoD            @ conversion ascii digit
    str r0,[r1,#command_min]     @ and store in minimum
    mov r8,#0                    @ line command ok
    add r5,#1                    @ increment indice
    b 7f
5:
    cmp r8,#0                    @ other name ?
    beq 6f
    mov r0,#0                    @ yes store zéro in minimum in prec 
    mov r1,#command_end
    mla r1,r5,r1,r7
    add r1,r1,#command_min
    str r0,[r1]
    add r5,#1                    @ and increment indice
6:
    mov r8,#1                    @ load name
    mov r1,#command_end
    mla r1,r5,r1,r7              @ store name in table
    str r4,[r1,#command_name_address]
7:                               @ loop suppress spaces
    ldrb r3,[r6,r2]
    cmp r3,#0
    beq 100f
    cmp r3,#' '
    addeq r2,r2,#1
    beq 7b
    
    add r4,r6,r2                 @ new start address
    b 1b
100:
    pop {r1-r8,lr}               @ restaur registers 
    bx lr                        @return
/******************************************************************/
/*     control load                                      */ 
/******************************************************************/
/* r0 contains string table           */
controlLoad:
    push {r1-r6,lr}              @ save  registers
    mov r5,r0
    mov r6,#0
    mov r2,#command_end
1:
    mla r3,r6,r2,r5             @ compute item address 
    ldr r1,[r3,#command_name_address]
    cmp r1,#0
    beq 100f
    ldr r0,iAdrszMessCtrlCom
    bl strInsertAtCharInc
    mov r4,r0
    ldr r0,[r3,#command_min]
    ldr r1,iAdrsZoneConv
    bl conversion10              @ call decimal conversion
    mov r0,r4
    ldr r1,iAdrsZoneConv         @ insert conversion in message
    bl strInsertAtCharInc
    bl affichageMess             @ display message

    add r6,r6,#1
    b 1b
    
100:
    pop {r1-r6,lr}               @ restaur registers 
    bx lr                        @return
iAdrszMessCtrlCom:       .int szMessCtrlCom

/***************************************************/
/*      ROUTINES INCLUDE                           */
/***************************************************/
.include "../affichage.inc"
Enter command (or <ctrl-c> to stop) : riG
RIGHT
Enter command (or <ctrl-c> to stop) : rePEAT
REPEAT
Enter command (or <ctrl-c> to stop) : copies
*error*
Enter command (or <ctrl-c> to stop) : put
PUT
Enter command (or <ctrl-c> to stop) : mo
MOVE
Enter command (or <ctrl-c> to stop) : rest
RESTORE
Enter command (or <ctrl-c> to stop) : types
*error*
Enter command (or <ctrl-c> to stop) : fup.
*error*
Enter command (or <ctrl-c> to stop) : 6
*error*
Enter command (or <ctrl-c> to stop) : poweRin
POWERINPUT
Enter command (or <ctrl-c> to stop) : ^C

AutoHotkey[edit]

table := "
(
   add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
)"

MsgBox % result := Abbreviations("riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin", table)
return

Abbreviations(str, table){
    Words := [], Expanded := []
    while pos := RegExMatch(table, "i)([a-z]+)(?:\s+(\d+))?", m, A_Index=1?1:pos+StrLen(m))
        Words[m1] := m2?m2:StrLen(m1)
    for i, abb in StrSplit(RegExReplace(str, " +", " "), " ")
    {
        for word, count in Words
            if (word ~= "i)^" abb) && (StrLen(abb) >= count)
            {
                StringUpper, word, word
                result .= word " "
                Expanded[abb] := true
                break
            }
        if !Expanded[abb]
            result .= "*error* "
    }
    return Trim(result, " ")
}
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

C[edit]

#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

const char* command_table =
  "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 "
  "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate "
  "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 "
  "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load "
  "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 "
  "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 "
  "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left "
  "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1";

typedef struct command_tag {
    char* cmd;
    size_t length;
    size_t min_len;
    struct command_tag* next;
} command_t;

// str is assumed to be all uppercase
bool command_match(const command_t* command, const char* str) {
    size_t olen = strlen(str);
    return olen >= command->min_len && olen <= command->length
        && strncmp(str, command->cmd, olen) == 0;
}

// convert string to uppercase
char* uppercase(char* str, size_t n) {
    for (size_t i = 0; i < n; ++i)
        str[i] = toupper((unsigned char)str[i]);
    return str;
}

void fatal(const char* message) {
    fprintf(stderr, "%s\n", message);
    exit(1);
}

void* xmalloc(size_t n) {
    void* ptr = malloc(n);
    if (ptr == NULL)
        fatal("Out of memory");
    return ptr;
}

void* xrealloc(void* p, size_t n) {
    void* ptr = realloc(p, n);
    if (ptr == NULL)
        fatal("Out of memory");
    return ptr;
}

char** split_into_words(const char* str, size_t* count) {
    size_t size = 0;
    size_t capacity = 16;
    char** words = xmalloc(capacity * sizeof(char*));
    size_t len = strlen(str);
    for (size_t begin = 0; begin < len; ) {
        size_t i = begin;
        for (; i < len && isspace((unsigned char)str[i]); ++i) {}
        begin = i;
        for (; i < len && !isspace((unsigned char)str[i]); ++i) {}
        size_t word_len = i - begin;
        if (word_len == 0)
            break;
        char* word = xmalloc(word_len + 1);
        memcpy(word, str + begin, word_len);
        word[word_len] = 0;
        begin += word_len;
        if (capacity == size) {
            capacity *= 2;
            words = xrealloc(words, capacity * sizeof(char*));
        }
        words[size++] = word;
    }
    *count = size;
    return words;
}

command_t* make_command_list(const char* table) {
    command_t* cmd = NULL;
    size_t count = 0;
    char** words = split_into_words(table, &count);
    for (size_t i = 0; i < count; ++i) {
        char* word = words[i];
        command_t* new_cmd = xmalloc(sizeof(command_t));
        size_t word_len = strlen(word);
        new_cmd->length = word_len;
        new_cmd->min_len = word_len;
        new_cmd->cmd = uppercase(word, word_len);
        if (i + 1 < count) {
            char* eptr = 0;
            unsigned long min_len = strtoul(words[i + 1], &eptr, 10);
            if (min_len > 0 && *eptr == 0) {
                free(words[i + 1]);
                new_cmd->min_len = min_len;
                ++i;
            }
        }
        new_cmd->next = cmd;
        cmd = new_cmd;
    }
    free(words);
    return cmd;
}

void free_command_list(command_t* cmd) {
    while (cmd != NULL) {
        command_t* next = cmd->next;
        free(cmd->cmd);
        free(cmd);
        cmd = next;
    }
}

const command_t* find_command(const command_t* commands, const char* word) {
    for (const command_t* cmd = commands; cmd != NULL; cmd = cmd->next) {
        if (command_match(cmd, word))
            return cmd;
    }
    return NULL;
}

void test(const command_t* commands, const char* input) {
    printf(" input: %s\n", input);
    printf("output:");
    size_t count = 0;
    char** words = split_into_words(input, &count);
    for (size_t i = 0; i < count; ++i) {
        char* word = words[i];
        uppercase(word, strlen(word));
        const command_t* cmd_ptr = find_command(commands, word);
        printf(" %s", cmd_ptr ? cmd_ptr->cmd : "*error*");
        free(word);
    }
    free(words);
    printf("\n");
}

int main() {
    command_t* commands = make_command_list(command_table);
    const char* input = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin";
    test(commands, input);
    free_command_list(commands);
    return 0;
}
Output:
 input: riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

C++[edit]

#include <algorithm>
#include <cctype>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

const char* command_table =
  "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 "
  "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate "
  "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 "
  "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load "
  "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 "
  "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 "
  "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left "
  "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1";

class command {
public:
    command(const std::string&, size_t);
    const std::string& cmd() const { return cmd_; }
    size_t min_length() const { return min_len_; }
    bool match(const std::string&) const;
private:
    std::string cmd_;
    size_t min_len_;
};

// cmd is assumed to be all uppercase
command::command(const std::string& cmd, size_t min_len)
    : cmd_(cmd), min_len_(min_len) {}

// str is assumed to be all uppercase
bool command::match(const std::string& str) const {
    size_t olen = str.length();
    return olen >= min_len_ && olen <= cmd_.length()
        && cmd_.compare(0, olen, str) == 0;
}

bool parse_integer(const std::string& word, int& value) {
    try {
        size_t pos;
        int i = std::stoi(word, &pos, 10);
        if (pos < word.length())
            return false;
        value = i;
        return true;
    } catch (const std::exception& ex) {
        return false;
    }
}

// convert string to uppercase
void uppercase(std::string& str) {
    std::transform(str.begin(), str.end(), str.begin(),
        [](unsigned char c) -> unsigned char { return std::toupper(c); });
}

class command_list {
public:
    explicit command_list(const char*);
    const command* find_command(const std::string&) const;
private:
    std::vector<command> commands_;
};

command_list::command_list(const char* table) {
    std::istringstream is(table);
    std::string word;
    std::vector<std::string> words;
    while (is >> word) {
        uppercase(word);
        words.push_back(word);
    }
    for (size_t i = 0, n = words.size(); i < n; ++i) {
        word = words[i];
        // if there's an integer following this word, it specifies the minimum
        // length for the command, otherwise the minimum length is the length
        // of the command string
        int len = word.length();
        if (i + 1 < n && parse_integer(words[i + 1], len))
            ++i;
        commands_.push_back(command(word, len));
    }
}

const command* command_list::find_command(const std::string& word) const {
    auto iter = std::find_if(commands_.begin(), commands_.end(),
        [&word](const command& cmd) { return cmd.match(word); });
    return (iter != commands_.end()) ? &*iter : nullptr;
}

std::string test(const command_list& commands, const std::string& input) {
    std::string output;
    std::istringstream is(input);
    std::string word;
    while (is >> word) {
        if (!output.empty())
            output += ' ';
        uppercase(word);
        const command* cmd_ptr = commands.find_command(word);
        if (cmd_ptr)
            output += cmd_ptr->cmd();
        else
            output += "*error*";
    }
    return output;
}

int main() {
    command_list commands(command_table);
    std::string input("riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin");
    std::string output(test(commands, input));
    std::cout << " input: " << input << '\n';
    std::cout << "output: " << output << '\n';
    return 0;
}
Output:
 input: riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Clojure[edit]

NOTE: Type Hints have been added here to indicate the types of function arguments and to make the program faster. They are not strictly necessary, since Clojure is a dynamically typed language (i.e., variable types are determined at runtime).

(defn words
  "Split string into words"
  [^String str]
  (.split (.stripLeading str) "\\s+"))

(defn join-words
  "Join words into a single string"
  ^String [strings]
  (String/join " " strings))

;; SOURCE: https://www.stackoverflow.com/a/38947571/12947681
(defn starts-with-ignore-case
  "Does string start with prefix (ignoring case)?"
  ^Boolean [^String string, ^String prefix]
  (.regionMatches string true 0 prefix 0 (count prefix)))

(defrecord CommandWord [^String word, ^long min-abbr-size])

(defn parse-cmd-table
  "Parse list of strings in command table into list of words and numbers
   If number is missing for any word, then the word is not included"
  ([cmd-table]
   (parse-cmd-table cmd-table 0 []))
  ([cmd-table i ans]
   (let [cmd-count (count cmd-table)]
     (if (= i cmd-count)
       ans
       (let [word (nth cmd-table i),
             [i num] (try [(+ i 2)
                           (Integer/parseInt ^String (nth cmd-table (inc i)))]
                          (catch NumberFormatException _
                            [(inc i) 0]))]
         (recur cmd-table i (conj ans (CommandWord. word num))))))))

;; cmd-table is a list of objects of type CommandWord (defined above)
(def cmd-table
  (->
   "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"
   words
   parse-cmd-table))

(defn abbr?
  "Is abbr a valid abbreviation of this command?"
  ^Boolean [^String abbr, ^CommandWord cmd]
  (let [{:keys [word min-abbr-size]} cmd]
    (and (<= min-abbr-size (count abbr) (count word))
         (starts-with-ignore-case word abbr))))

(defn solution
  "Find word matching each abbreviation in input (or *error* if not found),
   and join results into a string"
  ^String [^String str]
  (join-words (for [abbr (words str)]
                (if-let [{:keys [word]} (first (filter #(abbr? abbr %) cmd-table))]
                  (.toUpperCase ^String word)
                  "*error*"))))

;; Print solution for given test case
(println (solution "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"))
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Crystal[edit]

COMMAND_TABLE = 
  "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"

def parse_command_table(input : String)
    cmds = {} of String => String
    table = input.strip.split

    word = table[0].upcase
    table.each do |item|
        if /[0-9]+/.match(item)
            abbreviation_length = item.to_i
            (0..word.size-abbreviation_length).each do |i|
                cmds[word[(0..abbreviation_length-1+i)]] = word
            end
        else
            word = item.upcase
            cmds[word] = word
        end
    end
    return cmds
end

def parse_user_input(input : String?, commands)
    output = ""
    unless input.nil? 
        user_commands = input.strip.split
        user_commands.each do |command|
            command = command.upcase
            if commands.has_key?(command)
                output += commands[command]
            else
                output += "*error*"
            end
            output += " "
        end
    end
    return output
end

cmds = parse_command_table(COMMAND_TABLE)
puts "Input:"
user_input = gets
puts "Output:"
puts parse_user_input(user_input, cmds)
Output:
Input:
riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT 

D[edit]

class Abbreviations
{
	import std.array: split, join;
	import std.uni:toUpper;

	string[string] replaces;
	
	this(string table)
	{
		import std.ascii;
		import std.conv:parse;

		string saved;
		auto add = (string word){ if(word.length) replaces[word] = word; };

		foreach(word; table.toUpper.split)
			if(isDigit(word[0]))
			{
				for(int length=parse!int(word); length<=saved.length; ++length)
					replaces[saved[0..length]] = saved;
			} else
			{
				add(saved);
				saved = word;
			}
		add(saved);
	}

	string expand(string input) // pre-filled hashtable is used
	{
		import std.algorithm: map;
		return input.toUpper.split.map!(word => word in replaces ? replaces[word] : "*error*").join(" ");
	}
}

string table = "
   add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1";

string input = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin";
string expected = "RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT";

unittest // 'dmd -unittest ...' to activate it
{
	auto expander = new Abbreviations(table);
	assert(expander.expand(input) == expected);
	assert(expander.expand("") == "");
	assert(expander.expand("addadd") == "*error*");
}

void main()
{
	import std.stdio:writeln;

	writeln("Input : ", input);
	writeln("Output: ", new Abbreviations(table).expand(input));
}
Output:
Input : riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
Output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Delphi[edit]

This example does not show the output mentioned in the task description on this page (or a page linked to from here). Please ensure that it meets all task requirements and remove this message.
Note that phrases in task descriptions such as "print and display" and "print and show" for example, indicate that (reasonable length) output be a part of a language's solution.


Translation of: Go
program Abraviation_simple;

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

type
  TCommand = record
    value: string;
    len: integer;
  end;

function ReadTable(table: string): TArray<TCommand>;
begin
  var fields := table.Split([' '], TStringSplitOptions.ExcludeEmpty);
  var i := 0;
  var max := Length(fields);
  while i < max do
  begin
    var cmd := fields[i];
    var cmdLen := cmd.Length;
    inc(i);

    if i < max then
    begin
      var num: Integer;
      if TryStrToInt(fields[i], num) and (1 <= num) and (num < cmdLen) then
      begin
        cmdLen := num;
        inc(i);
      end;
    end;

    SetLength(result, Length(result) + 1);
    with result[High(result)] do
    begin
      value := cmd;
      len := cmdLen;
    end;
  end;
end;

function ValidateCommands(Commands: TArray<TCommand>; Words: TArray<string>):
  TArray<string>;
begin
  SetLength(result, 0);
  for var wd in Words do
  begin
    var matchFound := false;
    var wLen := wd.Length;
    for var i := 0 to High(Commands) do
    begin
      var command := Commands[i];
      if (command.len = 0) or (wLen < command.len) or (wLen > command.value.Length) then
        Continue;
      var c := command.value.ToUpper;
      var w := wd.ToUpper;
      if c.StartsWith(w) then
      begin
        SetLength(result, Length(result) + 1);
        result[High(result)] := c;
        matchFound := true;
        Break;
      end;
    end;
    if not matchFound then
    begin
      SetLength(result, Length(result) + 1);
      result[High(result)] := '*error*';
    end;
  end;
end;

procedure PrintResults(words, results: TArray<string>);
begin
  Writeln('user words:');
  for var w in words do
    write(^I, w);
  Writeln(#10, 'full words:'^I, string.join(^I, results));
end;

const
  table = '' +
    'add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 ' +
    'compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate ' +
    '3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 ' +
    'forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load ' +
    'locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 ' +
    'msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 ' +
    'refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left ' +
    '2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1 ';

const
  SENTENCE = 'riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin';

begin
  var Commands := ReadTable(table);
  var Words := SENTENCE.Split([' '], TStringSplitOptions.ExcludeEmpty);

  var results := ValidateCommands(Commands, Words);

  PrintResults(Words, results);

  Readln;
end.

Factor[edit]

USING: arrays assocs combinators formatting fry grouping.extras
kernel literals math math.parser multiline sequences
splitting.extras unicode ;
IN: rosetta-code.abbr-simple

CONSTANT: input $[
"riG   rePEAT copies  put mo   rest    types   fup.    6       "
"poweRin" append
]

<<     ! Make the following two words available at parse time.

: abbr-pair ( first second -- seq/f )
    {
        { [ 2dup drop [ digit? ] all? ] [ 2drop f ] }
        {
            [ 2dup nip [ Letter? ] all? ]
            [ drop >upper 0 2array ]
        }
        [ [ >upper ] [ string>number ] bi* 2array ]
    } cond ;

: parse-commands ( seq -- seq )
    " \n" split-harvest [ abbr-pair ] 2clump-map sift ;

>>

CONSTANT: commands $[
HEREDOC: END
add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange
Cinsert 2  Clast 3 compress 4 copy 2 count 3 Coverlay 3 cursor 3
delete 3 Cdelete 2  down 1  duplicate 3 xEdit 1 expand 3 extract
3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 forward
2  get  help 1  hexType 4  input 1 powerInput 3  join  1 split 2
spltJOIN load locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix
2  macro  merge 2  modify  3  move 2 msg  next 1 overlay 1 parse
preserve 4 purge 3 put putD query 1 quit  read recover 3 refresh
renum 3 repeat 3 replace 1 Creplace  2 reset 3 restore 4 rgtLEFT
right 2 left 2  save  set  shift 2  si  sort sos  stack 3 status
4 top  transfer 3  type 1  up 1
END
parse-commands
]

: valid-abbrevs ( assoc seq -- assoc )
    dup '[ [ _ head? ] [ _ length <= ] bi* and ] assoc-filter ;

: find-command ( seq -- seq )
    >upper [ commands ] dip valid-abbrevs
    [ "*error*" ] [ first first ] if-empty ;

: (find-commands) ( seq -- seq )
    " " split-harvest [ find-command ] map " " join ;

: find-commands ( seq -- seq )
    dup empty? not [ (find-commands) ] when ;

: show-commands ( seq -- )
    dup find-commands " Input: \"%s\"\nOutput: \"%s\"\n" printf
    ;

: main ( -- ) input "" [ show-commands ] bi@ ;

MAIN: main
Output:
 Input: "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
Output: "RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT"
 Input: ""
Output: ""

Forth[edit]

Works with any ANS Forth

Needs the FMS-SI (single inheritance) library code located here: http://soton.mpeforth.com/flag/fms/index.html

include FMS-SI.f
include FMS-SILib.f

${ add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1 } 
   value list  ' upper: list map:

: compare' { adr len $obj -- f }
  len $obj size: > if false exit then
  adr len $obj @: drop len compare 0= ;

: <= ( n1 n2 = f) 1+ swap > ;     

: abbrev 0 0 { adr len obj1 obj2 -- }
  list uneach:
  list each: drop to obj1 
  begin
   list each: 
  while
   to obj2
   obj2 @: >integer
     if  \ word followed by a number
         len <= if adr len obj1 compare'
                   if obj1 p: exit then
                then list each: if to obj1  else ." *error* " exit then
     else \ word not followed by a number
          adr len obj1 @: compare 0=
          if obj1 p: exit then
          obj2 to obj1
     then 
  repeat ; 

${ riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin }
  value input-list  ' upper: input-list map:

: valid-input ( adr len -- f)
  over + swap do i c@ isalpha 0= if ." *error* " unloop false exit then loop true ;

: run
  begin
    input-list each:
  while
    dup @: valid-input
    if @: abbrev space else drop then
  repeat ;


run RIGHT REPEAT *error*  PUT MOVE RESTORE *error*  *error* *error* POWERINPUT ok


FutureBasic[edit]

_window = 1
begin enum 1
  _userStringFld
  _validateBtn
  _resultsStringFld
end enum

void local fn BuildWindow
  window _window, @"Abbreviations, simple", (0,0,600,268)
  WindowSetContentMinSize( _window, fn CGSizeMake( 200, 268 ) )
  WindowSetContentMaxSize( _window, fn CGSizeMake( 10000, 268 ) )
  
  textfield _userStringFld,, @"riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin", (20,152,560,96)
  TextFieldSetPlaceholderString( _userStringFld, @"Enter commands" )
  ViewSetAutoresizingMask( _userStringFld, NSViewWidthSizable )
  
  button _validateBtn,,, @"Validate", (259,117,83,32)
  ViewSetAutoresizingMask( _validateBtn, NSViewMinXMargin + NSViewMaxXMargin )
  
  textfield _resultsStringFld,,, (20,20,560,96)
  TextFieldSetEditable( _resultsStringFld, NO )
  TextFieldSetSelectable( _resultsStringFld, YES )
  ViewSetAutoresizingMask( _resultsStringFld, NSViewWidthSizable )
end fn

local fn Commands as CFArrayRef
  CFStringRef       cmd, string
  long              abbrLen
  CFMutableArrayRef commands = fn MutableArrayWithCapacity(0)
  ScannerRef        scanner
  
  string = @"   add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3"
  string = fn StringByAppendingString( string, @"   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate" )
  string = fn StringByAppendingString( string, @"   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2" )
  string = fn StringByAppendingString( string, @"   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load" )
  string = fn StringByAppendingString( string, @"   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2" )
  string = fn StringByAppendingString( string, @"   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3" )
  string = fn StringByAppendingString( string, @"   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left" )
  string = fn StringByAppendingString( string, @"   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1" )
  
  scanner = fn ScannerWithString( string )
  while ( fn ScannerIsAtEnd( scanner ) == NO )
    if ( fn ScannerScanUpToCharactersFromSet( scanner, fn CharacterSetWhitespaceAndNewlineSet, @cmd ) )
      abbrLen = 0
      fn ScannerScanInteger( scanner, @abbrLen )
      MutableArrayAddObject( commands, @{@"cmd":cmd,@"len":@(abbrLen)} )
    end if
  wend
end fn = commands

void local fn Validate
  CFArrayRef         commands, words
  CFStringRef        userString, result, wd, cmd
  long               wordCount, i, wordLen, abbrLen
  CFMutableStringRef results
  CFDictionaryRef    dict
  BOOL               found
  
  commands   = fn Commands
  userString = fn ControlStringValue( _userStringFld )
  words      = fn StringComponentsSeparatedByCharactersInSet( userString, fn CharacterSetWhitespaceAndNewlineSet )
  results    = fn MutableStringWithCapacity( 0 )
  wordCount  = len( words )
  
  for i = 0 to wordCount - 1
    found = NO
    result = @"*error* "
    wd = words[i]
    wordLen = len( wd )
    if ( wordLen )
      
      for dict in commands
        cmd = dict[@"cmd"]
        abbrLen = fn NumberIntegerValue(dict[@"len"])
        
        if ( abbrLen != 0 and wordLen >= abbrLen )
          found = fn StringHasPrefix( lcase( cmd ), lcase( wd ) )
        else
          found = fn StringIsEqual( lcase( cmd ), lcase( wd ) )
        end if
        
        if ( found )
          result = fn StringWithFormat( @"%@ ",ucase( cmd ) )
          break
        end if
        
      next
      
      MutableStringAppendString( results, result )
    end if
  next
  
  ControlSetStringValue( _resultsStringFld, results )
end fn


void local fn DoDialog( ev as long, tag as long )
  select ( ev )
    case _btnClick : fn Validate
  end select
end fn


editmenu 1
fn BuildWindow

on dialog fn DoDialog

HandleEvents
Output:
user string:    riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin    
results string: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Go[edit]

Translation of: Kotlin
package main

import (
	"io"
	"os"
	"strconv"
	"strings"
	"text/tabwriter"
)

func readTable(table string) ([]string, []int) {
	fields := strings.Fields(table)
	var commands []string
	var minLens []int

	for i, max := 0, len(fields); i < max; {
		cmd := fields[i]
		cmdLen := len(cmd)
		i++

		if i < max {
			num, err := strconv.Atoi(fields[i])
			if err == nil && 1 <= num && num < cmdLen {
				cmdLen = num
				i++
			}
		}

		commands = append(commands, cmd)
		minLens = append(minLens, cmdLen)
	}

	return commands, minLens
}

func validateCommands(commands []string, minLens []int, words []string) []string {
	var results []string
	for _, word := range words {
		matchFound := false
		wlen := len(word)
		for i, command := range commands {
			if minLens[i] == 0 || wlen < minLens[i] || wlen > len(command) {
				continue
			}
			c := strings.ToUpper(command)
			w := strings.ToUpper(word)
			if strings.HasPrefix(c, w) {
				results = append(results, c)
				matchFound = true
				break
			}
		}
		if !matchFound {
			results = append(results, "*error*")
		}
	}
	return results
}

func printResults(words []string, results []string) {
	wr := tabwriter.NewWriter(os.Stdout, 0, 1, 1, ' ', 0)
	io.WriteString(wr, "user words:")
	for _, word := range words {
		io.WriteString(wr, "\t"+word)
	}
	io.WriteString(wr, "\n")
	io.WriteString(wr, "full words:\t"+strings.Join(results, "\t")+"\n")
	wr.Flush()
}

func main() {
	const table = "" +
		"add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 " +
		"compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate " +
		"3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 " +
		"forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load " +
		"locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 " +
		"msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 " +
		"refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left " +
		"2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1 "

	const sentence = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"

	commands, minLens := readTable(table)
	words := strings.Fields(sentence)

	results := validateCommands(commands, minLens, words)

	printResults(words, results)
}
Output:
user words:  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin    
full words:  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Haskell[edit]

Translation of: Python
import Data.List (find, isPrefixOf)
import Data.Char (isDigit, toUpper)
import Data.Maybe (maybe)

withExpansions :: [(String, Int)] -> String -> String
withExpansions tbl s = unwords $ expanded tbl <$> words s

expanded :: [(String, Int)] -> String -> String
expanded tbl k = maybe "*error" fst (expand k)
  where
    expand [] = Just ([], 0)
    expand s =
      let u = toUpper <$> s
          lng = length s
      in find (\(w, n) -> lng >= n && isPrefixOf u w) tbl

cmdsFromString :: String -> [(String, Int)]
cmdsFromString s =
  let go w@(x:_) (xs, n)
        | isDigit x = (xs, read w :: Int)
        | otherwise = ((toUpper <$> w, n) : xs, 0)
  in fst $ foldr go ([], 0) (words s)

-- TESTS --------------------------------------------------
table :: [(String, Int)]
table =
  cmdsFromString
    "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1 \
    \Schange Cinsert 2  Clast 3 compress 4 copy 2 count 3 Coverlay 3 \
    \cursor 3  delete 3 Cdelete 2  down 1  duplicate 3 xEdit 1 expand 3 \
    \extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 \
    \forward 2  get  help 1 hexType 4 input 1 powerInput 3  join 1 \
    \split 2 spltJOIN load locate 1 Clocate 2 lowerCase 3 upperCase 3 \
    \Lprefix 2  macro  merge 2 modify 3 move 2 msg  next 1 overlay 1 \
    \parse preserve 4 purge 3 put putD query 1 quit read recover 3 \
    \refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 \
    \rgtLEFT right 2 left 2  save  set  shift 2  si  sort  sos stack 3 \
    \status 4 top  transfer 3  type 1  up 1"

main :: IO ()
main = do
  let unAbbrev = withExpansions table
  print $
    unAbbrev
      "riG   rePEAT copies  put mo   rest    types   fup.    6      poweRin"
  print $ unAbbrev ""
Output:
"RIGHT REPEAT *error PUT MOVE RESTORE *error *error *error POWERINPUT"
""

J[edit]

ctable=:|:(({.;~{:@(_,".)@;@}.);.1~ _2<nc) cut {{)n
   add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
}} -.LF
 
findmatch=: {{
  lens=. >{.ctable
  for_ndx. I.y-:"1&tolower (#y){.&> list do. cmd=. ;(<1,ndx){ctable
    if. (#y) >: ndx{lens do. toupper cmd return. end.
    if. y -: cmd do. toupper cmd return. end.
  end.
  '*error*'
}}L:0

Task:

   ;:inv findmatch cut ' riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin'
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Java[edit]

Translation of: C++
import java.util.*;

public class Abbreviations {
    public static void main(String[] args) {
        CommandList commands = new CommandList(commandTable);
        String input = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin";
        System.out.println(" input: " + input);
        System.out.println("output: " + test(commands, input));
    }

    private static String test(CommandList commands, String input) {
        StringBuilder output = new StringBuilder();
        Scanner scanner = new Scanner(input);
        while (scanner.hasNext()) {
            String word = scanner.next();
            if (output.length() > 0)
                output.append(' ');
            Command cmd = commands.findCommand(word);
            if (cmd != null)
                output.append(cmd.cmd);
            else
                output.append("*error*");
        }
        return output.toString();
    }

    private static String commandTable =
        "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 " +
        "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate " +
        "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 " +
        "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load " +
        "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 " +
        "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 " +
        "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left " +
        "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1";

    private static class Command {
        private Command(String cmd, int minLength) {
             this.cmd = cmd;
             this.minLength = minLength;
        }
        private boolean match(String str) {
            int olen = str.length();
            return olen >= minLength && olen <= cmd.length()
                && cmd.regionMatches(true, 0, str, 0, olen);
        }
        private String cmd;
        private int minLength;
    }

    private static Integer parseInteger(String word) {
        try {
            return Integer.valueOf(word);
        } catch (NumberFormatException ex) {
            return null;
        }
    }

    private static class CommandList {
        private CommandList(String table) {
            Scanner scanner = new Scanner(table);
            List<String> words = new ArrayList<>();
            while (scanner.hasNext()) {
                String word = scanner.next();
                words.add(word.toUpperCase());
            }
            for (int i = 0, n = words.size(); i < n; ++i) {
                String word = words.get(i);
                // if there's an integer following this word, it specifies the minimum
                // length for the command, otherwise the minimum length is the length
                // of the command string
                int len = word.length();
                if (i + 1 < n) {
                    Integer number = parseInteger(words.get(i + 1));
                    if (number != null) {
                        len = number.intValue();
                        ++i;
                    }
                }
                commands.add(new Command(word, len));
            }
        }
        private Command findCommand(String word) {
            for (Command command : commands) {
                if (command.match(word))
                    return command;
            }
            return null;
        }
        private List<Command> commands = new ArrayList<>();
    }
}
Output:
 input: riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

JavaScript[edit]

Translation of: Haskell
Translation of: Python
(() => {
    'use strict';

    // withExpansions :: [(String, Int)] -> String -> String
    const withExpansions = tbl => s =>
        unwords(map(expanded(tbl), words(s)));

    // expanded :: [(String, Int)] -> String -> String
    const expanded = tbl => s => {
        const
            lng = s.length,
            u = toUpper(s),
            p = wn => {
                const [w, n] = Array.from(wn);
                return lng >= n && isPrefixOf(u, w);
            }
        return maybe(
            '*error*',
            fst,
            0 < lng ? (
                find(p, tbl)
            ) : Just(Tuple([], 0))
        );
    };

    // cmdsFromString :: String -> [(String, Int)]
    const cmdsFromString = s =>
        fst(foldr(
            (w, a) => {
                const [xs, n] = Array.from(a);
                return isDigit(head(w)) ? (
                    Tuple(xs, parseInt(w, 10))
                ) : Tuple(
                    [Tuple(toUpper(w), n)].concat(xs),
                    0
                );
            },
            Tuple([], 0),
            words(s)
        ));

    // TEST -----------------------------------------------
    const main = () => {

        // table :: [(String, Int)]
        const table = cmdsFromString(
            `add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1
            Schange Cinsert 2  Clast 3 compress 4 copy 2 count 3 Coverlay 3
            cursor 3  delete 3 Cdelete 2  down 1  duplicate 3 xEdit 1 expand 3
            extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
            forward 2  get  help 1 hexType 4 input 1 powerInput 3  join 1
            split 2 spltJOIN load locate 1 Clocate 2 lowerCase 3 upperCase 3
            Lprefix 2  macro  merge 2 modify 3 move 2 msg  next 1 overlay 1
            parse preserve 4 purge 3 put putD query 1 quit read recover 3
            refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4
            rgtLEFT right 2 left 2  save  set  shift 2  si  sort  sos stack 3
            status 4 top  transfer 3  type 1  up 1`
        );

        return fTable(
            'Abbreviation tests:\n',
            s => "'" + s + "'",
            s => "\n\t'" + s + "'",
            withExpansions(table),
            [
                'riG   rePEAT copies  put mo   rest    types   fup.    6      poweRin',
                ''
            ]
        );
    };

    // GENERIC FUNCTIONS ----------------------------------

    // Just :: a -> Maybe a
    const Just = x => ({
        type: 'Maybe',
        Nothing: false,
        Just: x
    });

    // Nothing :: Maybe a
    const Nothing = () => ({
        type: 'Maybe',
        Nothing: true,
    });

    // Tuple (,) :: a -> b -> (a, b)
    const Tuple = (a, b) => ({
        type: 'Tuple',
        '0': a,
        '1': b,
        length: 2
    });

    // compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
    const compose = (f, g) => x => f(g(x));

    // find :: (a -> Bool) -> [a] -> Maybe a
    const find = (p, xs) => {
        for (let i = 0, lng = xs.length; i < lng; i++) {
            if (p(xs[i])) return Just(xs[i]);
        }
        return Nothing();
    };

    // flip :: (a -> b -> c) -> b -> a -> c
    const flip = f =>
        1 < f.length ? (
            (a, b) => f(b, a)
        ) : (x => y => f(y)(x));

    // foldl1 :: (a -> a -> a) -> [a] -> a
    const foldl1 = (f, xs) =>
        1 < xs.length ? xs.slice(1)
        .reduce(f, xs[0]) : xs[0];

    // foldr :: (a -> b -> b) -> b -> [a] -> b
    const foldr = (f, a, xs) => xs.reduceRight(flip(f), a);

    // fst :: (a, b) -> a
    const fst = tpl => tpl[0];

    // fTable :: String -> (a -> String) ->
    //                     (b -> String) -> (a -> b) -> [a] -> String
    const fTable = (s, xShow, fxShow, f, xs) => {
        // Heading -> x display function ->
        //           fx display function ->
        //    f -> values -> tabular string
        const
            ys = map(xShow, xs),
            w = maximum(map(length, ys)),
            rows = zipWith(
                (a, b) => justifyRight(w, ' ', a) + ' -> ' + b,
                ys,
                map(compose(fxShow, f), xs)
            );
        return s + '\n' + unlines(rows);
    };

    // head :: [a] -> a
    const head = xs => xs.length ? xs[0] : undefined;

    // isDigit :: Char -> Bool
    const isDigit = c => {
        const n = ord(c);
        return 48 <= n && 57 >= n;
    };

    // isPrefixOf takes two lists or strings and returns
    // true iff the first is a prefix of the second.

    // isPrefixOf :: [a] -> [a] -> Bool
    // isPrefixOf :: String -> String -> Bool
    const isPrefixOf = (xs, ys) => {
        const go = (xs, ys) => {
            const intX = xs.length;
            return 0 < intX ? (
                ys.length >= intX ? xs[0] === ys[0] && go(
                    xs.slice(1), ys.slice(1)
                ) : false
            ) : true;
        };
        return 'string' !== typeof xs ? (
            go(xs, ys)
        ) : ys.startsWith(xs);
    };

    // justifyRight :: Int -> Char -> String -> String
    const justifyRight = (n, cFiller, s) =>
        n > s.length ? (
            s.padStart(n, cFiller)
        ) : s;

    // Returns Infinity over objects without finite length.
    // This enables zip and zipWith to choose the shorter
    // argument when one is non-finite, like cycle, repeat etc

    // length :: [a] -> Int
    const length = xs =>
        (Array.isArray(xs) || 'string' === typeof xs) ? (
            xs.length
        ) : Infinity;

    // map :: (a -> b) -> [a] -> [b]
    const map = (f, xs) =>
        (Array.isArray(xs) ? (
            xs
        ) : xs.split('')).map(f);

    // maximum :: Ord a => [a] -> a
    const maximum = xs =>
        0 < xs.length ? (
            foldl1((a, x) => x > a ? x : a, xs)
        ) : undefined;

    // maybe :: b -> (a -> b) -> Maybe a -> b
    const maybe = (v, f, m) =>
        m.Nothing ? v : f(m.Just);

    // ord :: Char -> Int
    const ord = c => c.codePointAt(0);

    // take :: Int -> [a] -> [a]
    // take :: Int -> String -> String
    const take = (n, xs) =>
        'GeneratorFunction' !== xs.constructor.constructor.name ? (
            xs.slice(0, n)
        ) : [].concat.apply([], Array.from({
            length: n
        }, () => {
            const x = xs.next();
            return x.done ? [] : [x.value];
        }));

    // toUpper :: String -> String
    const toUpper = s => s.toLocaleUpperCase();

    // unlines :: [String] -> String
    const unlines = xs => xs.join('\n');

    // unwords :: [String] -> String
    const unwords = xs => xs.join(' ');

    // words :: String -> [String]
    const words = s => s.split(/\s+/);

    // Use of `take` and `length` here allows zipping with non-finite lists
    // i.e. generators like cycle, repeat, iterate.

    // zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    const zipWith = (f, xs, ys) => {
        const
            lng = Math.min(length(xs), length(ys)),
            as = take(lng, xs),
            bs = take(lng, ys);
        return Array.from({
            length: lng
        }, (_, i) => f(as[i], bs[i], i));
    };

    // MAIN ---
    return main();
})();
Output:
Abbreviation tests:

'riG   rePEAT copies  put mo   rest    types   fup.    6      poweRin' -> 
    'RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT'
                                                                    '' -> 
    ''

Julia[edit]

const commandtable = """
add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"""

function makedict(tbl)
    str = split(uppercase(tbl), r"\s+")
    dict = Dict{String, String}()
    for (i, s) in enumerate(str)
        if (n = tryparse(Int, s)) != nothing
            dict[str[i-1][1:n]] = str[i-1]
        else
            dict[s] = s
        end
    end
    dict
end

function okabbrev(dict, abb)
    for i in length(abb):-1:1
        if haskey(dict, abb[1:i])
            com = dict[abb[1:i]]
            if length(abb) <= length(com) && abb == com[1:length(abb)]
                return dict[abb[1:i]]
            end
        end
    end
    return "*error*"
end

formattedprint(arr, n) =  (for s in arr print(rpad(s, n)) end; println())

function teststring(str)
    d = makedict(commandtable)
    commands = split(str, r"\s+")
    formattedprint(commands, 9)
    formattedprint([okabbrev(d, uppercase(s)) for s in commands], 9)
end

teststring("riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin")
Output:

riG rePEAT copies put mo rest types fup. 6 poweRin RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Kotlin[edit]

import java.util.Locale

private const val table = "" +
        "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 " +
        "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate " +
        "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 " +
        "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load " +
        "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 " +
        "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 " +
        "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left " +
        "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1 "

private data class Command(val name: String, val minLen: Int)

private fun parse(commandList: String): List<Command> {
    val commands = mutableListOf<Command>()
    val fields = commandList.trim().split(" ")
    var i = 0
    while (i < fields.size) {
        val name = fields[i++]
        var minLen = name.length
        if (i < fields.size) {
            val num = fields[i].toIntOrNull()
            if (num != null && num in 1..minLen) {
                minLen = num
                i++
            }
        }
        commands.add(Command(name, minLen))
    }
    return commands
}

private fun get(commands: List<Command>, word: String): String? {
    for ((name, minLen) in commands) {
        if (word.length in minLen..name.length && name.startsWith(word, true)) {
            return name.toUpperCase(Locale.ROOT)
        }
    }
    return null
}

fun main(args: Array<String>) {
    val commands = parse(table)
    val sentence = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
    val words = sentence.trim().split(" ")

    val results = words.map { word -> get(commands, word) ?: "*error*" }

    val paddedUserWords = words.mapIndexed { i, word -> word.padEnd(results[i].length) }
    println("user words:  ${paddedUserWords.joinToString(" ")}")
    println("full words:  ${results.joinToString(" ")}")
}
Output:
user words:  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin    
full words:  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT 

Lua[edit]

abbr = {
  define = function(self, cmdstr)
    local cmd
    self.hash = {}
    for word in cmdstr:upper():gmatch("%S+") do
      if cmd then
        local n = tonumber(word)
        for len = n or #cmd, #cmd do
          self.hash[cmd:sub(1,len)] = cmd
        end
        cmd = n==nil and word or nil
      else
        cmd = word
      end
    end
  end,
  expand = function(self, input)
    local output = {}
    for word in input:upper():gmatch("%S+") do
      table.insert(output, self.hash[word] or "*error*")
    end
    return table.concat(output, " ")
  end
}
abbr:define[[
  add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
  compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
  3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
  forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
  locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
  msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
  refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
  2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
]]
local input = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
print("Input:", input)
print("Output:", abbr:expand(input))
Output:
Input:  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
Output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

M2000 Interpreter[edit]

Using a List Object[edit]

Object Queue is a list (using a hash table) which can hold same keys (strings or numbers or mix of them). Always the Exist(aQueuePointer, "word") set the internal index to the last key with name "word" if return true. We read the item in that index using Eval$(aQueuePointer) for string value, or Eval(aQueuePointer) for aritmetic value. We can't delete keys from anywhere, but only from the last entries using Drop statement to drop a number of keys. Here we didn't use drop, we have only a table of words.

Module Abbreviations_Simple {
	Function Lex {
		a$={add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
		   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
		   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
		   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
		   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
		   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
		   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
		   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
		}
		const crlftab$={
		}+chr$(9)
		
		Lex=Queue
		Word$=""
		dim part$()
		part$()=piece$(trim$(filter$(a$, crlftab$)), " ")
		for i=0 to len(part$())-1
		if part$(i)<>"" then
			k=val(part$(i))
			if k=0 then
				if Word$<>"" then Append Lex, Word$:=Word$
				Word$=ucase$(part$(i))
			else
				for j=k to len(Word$)
				Append Lex, left$(Word$,j):=Word$
				next j
				word$=""
			end if
		end if
		next i
		if Word$<>"" then Append Lex, Word$:=Word$
		=Lex
	}
	Parse$=Lambda$ Lex=Lex() (a$) -> {
		Dim part$()
		Rep$=""
		part$()=piece$(a$," ")
		if len(part$())=0 then exit
		for i=0 to len(part$())-1
		if part$(i)<>"" then
			if exist(Lex, ucase$(part$(i))) then
				Rep$+=if$(Rep$=""->"", " ")+Eval$(lex)
			else
				Rep$+=if$(Rep$=""->"", " ")+"*error*"
			end if
		end if
		next i
		=Rep$
	}
	Print Parse$("riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin")
	Print Parse$("riG   macro copies macr")
	Print Parse$("")=""
}
Abbreviations_Simple
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
RIGHT MACRO *error* *error*
True

Using simple string[edit]

Here we use just a string to hold the words and the Instr() function to search for each abbreviation.

Module Abbreviations_Simple_2 {
	Function Lex$ {
		a$={add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
		   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
		   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
		   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
		   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
		   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
		   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
		   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
		}
		const crlftab$={
		}+chr$(9)
		
		Lex$=""
		Word$=""
		dim part$()
		part$()=piece$(trim$(filter$(a$, crlftab$)), " ")
		for i=0 to len(part$())-1
		if part$(i)<>"" then
			k=val(part$(i))
			if k=0 then
				if Word$<>"" then Lex$+="#"+Word$+" 0"
				Word$=ucase$(part$(i))
			else
				Lex$+="#"+ Word$+str$(k)
				word$=""
			end if
		end if
		next i
		if Word$<>"" then Lex$+="#"+Word$+" 0"
		=Lex$
	}
	Parse$=Lambda$ Lex$=Lex$() (a$) -> {
		Dim part$()
		Rep$=""
		part$()=piece$(a$," ")
		if len(part$())=0 then exit
		for i=0 to len(part$())-1
		if part$(i)<>"" then
			j=1
			do
				j=instr(Lex$, "#"+ucase$(part$(i)), j)
				if j=0 then exit
				q=instr(Lex$, " ", j+1)
				if Val(Mid$(lex$, q,10))=0 then
					if Mid$(Lex$, j+1, q-j)=ucase$(part$(i))+" " then exit
				else.if len(part$(i))>=Val(Mid$(lex$, q,10)) then
					exit
				end if
				j++
			Always
			if j>0 then
				Rep$+=if$(Rep$=""->"", " ")+Mid$(Lex$, j+1, q-j-1)
			else
				Rep$+=if$(Rep$=""->"", " ")+"*error*"
			end if
		end if
		next i
		=Rep$
	}
	Print Parse$("riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin")
	Print Parse$("riG   macro copies macr")
	Print Parse$("")=""
}
Abbreviations_Simple_2
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
RIGHT MACRO *error* *error*
True

Mathematica/Wolfram Language[edit]

ClearAll[ct, FunctionMatchQ, ValidFunctionQ, ProcessString]
ct = "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1";
ct = FixedPoint[StringReplace[{"\n" -> "", Longest[" " ..] -> " "}], ct];
ct = StringSplit[ct, " "];
ct = SequenceReplace[ct, {x_, y : (Alternatives @@ (ToString /@ Range[1, 9]))} :> {x, ToExpression@y}];
ct = If[MatchQ[#, {_, _Integer}], #, {#, 1}] & /@ ct;
FunctionMatchQ[{func_String, min_Integer}, test_String] := 
 Module[{max, l},
  max = StringLength[func];
  l = StringLength[test];
  If[min <= l <= max,
   If[StringStartsQ[func, test, IgnoreCase -> True],
    True
    ,
    False
    ]
   ,
   False
   ]
  ]
ValidFunctionQ[test_String] := Module[{val},
  val = SelectFirst[ct, FunctionMatchQ[#, test] &, Missing[]];
  If[MissingQ[val], "*error*", ToUpperCase[First@val]]
  ]
ProcessString[test_String] := Module[{parts},
  parts = StringSplit[test];
  StringRiffle[ValidFunctionQ /@ parts, " "]
  ]
ProcessString["riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"]
Output:
"RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT"

MiniScript[edit]

c = "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2 Clast 3" +
 " compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate" +
 " 3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2" +
 " forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load" +
 " locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2" +
 " msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3" +
 " refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left" +
 " 2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"
 
minLen = {}
lastItem = ""
for item in c.split
    if item == "" then continue
    item = item.upper
    if lastItem and item[0] >= "0" and item[0] <= "9" then
        minLen[lastItem] = val(item)
        lastItem = ""
    else
        minLen[item] = null
        lastItem = item
    end if
end for
 
check = function(word)
    word = word.upper
    for key in minLen.indexes
        if key[:word.len] != word then continue
        min = minLen[key]
        if min and word.len < min then continue
        return key
    end for
    return "*error*"
end function
 
input = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
 
output = []
for word in input.split
    if word == "" then continue
    output.push check(word)
end for
print output.join
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Nim[edit]

Translation of: Python

Adapted from Python version with several modifications.

import parseutils
import strutils
import tables

const Commands =
  "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 " &
  "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate " &
  "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 " &
  "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load " &
  "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 " &
  "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 " &
  "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left " &
  "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"

#---------------------------------------------------------------------------------------------------

proc abbrevationLengths(commands: string): Table[string, int] =
  ## Find the minimal abbreviation length for each word.
  ## A word that does not have minimum abbreviation length specified
  ## gets it's full length as the minimum.

  var word = ""
  for item in commands.splitWhitespace():
    var n: int
    if item.parseInt(n) == 0:
      # Not a number.
      if word.len != 0:
        # No minimal length specified for the word.
        result[word] = word.len
      word = item
    else:
      # Got an integer.
      if word.len == 0:
        raise newException(ValueError, "Invalid position for number: " & $n)
      result[word] = n
      word = ""

#---------------------------------------------------------------------------------------------------

proc abbreviations(commandTable: Table[string, int]): Table[string, string] =
  ## For each command insert all possible abbreviations.
  for command, minlength in commandTable.pairs:
    for length in minLength..command.len:
      let abbr = command[0..<length].toLower
      result[abbr] = command.toUpper

#---------------------------------------------------------------------------------------------------

proc parse(words: seq[string]; abbrevTable: Table[string, string]): seq[string] =
  ## Parse a list of words and return the list of full words (or *error*).
  for word in words:
    result.add(abbrevTable.getOrDefault(word.toLower, "*error*"))

#---------------------------------------------------------------------------------------------------

let commandTable = Commands.abbrevationLengths()
let abbrevTable = commandTable.abbreviations()

while true:

  try:
    stdout.write "Input? "
    let userWords = stdin.readline().strip().splitWhitespace()
    let fullWords = userWords.parse(abbrevTable)
    stdout.write("\nUser words: ")
    for i, word in userWords:
      stdout.write(word.alignLeft(fullWords[i].len) & ' ')
    stdout.write("\nFull words: ")
    for word in fullWords:
      stdout.write(word & ' ')
    stdout.write("\n\n")

  except EOFError:
    echo ""
    break
Output:

User words: riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin    
Full words: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT 

Input? 

OCaml[edit]

open String

let table_as_string =
  "add 1 alter 3  backup 2  bottom 1  Cappend 2  change 1 \
   Schange  Cinsert 2  Clast 3 compress 4 copy 2 count 3 \
   Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate 3 \
   xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 \
   Cfind 2 findUP 3 fUP 2 forward 2  get  help 1 hexType 4 \
   input 1 powerInput 3  join 1 split 2 spltJOIN load locate 1 \
   Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 \
   modify 3 move 2 msg  next 1 overlay 1 parse preserve 4 purge 3 \
   put putD query 1 quit  read recover 3 refresh renum 3 repeat 3 \
   replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left 2 \
   save  set  shift 2  si  sort  sos  stack 3 status 4 top \
   transfer 3  type 1  up 1"

The interesting part below is the compare function. We'll use it when storing our entries ( {"add";1}, {"alter";3}, etc ) and when looking for a word, from a given abbreviation. For the former, a simple comparison function on strings is enough, but for the latter, we need to ensure that the word corresponds to the abbreviation (the abbreviation is a substring of the word and the abbreviation length is sufficient).

module Entry = struct
  type t = { word : string ; min : int }
  let compare e1 e2 =
    let n1 = length e1.word in
    if n1 < e2.min || n1 > length e2.word then
      compare e1.word e2.word
    else
      compare (sub e1.word 0 n1) (sub e2.word 0 n1)
end

module Table = Set.Make(Entry)

The few functions below are used to build the table from the string at the beginning.

let clean_strings strs =
  List.filter (fun w -> w <> "" && w <> " ") strs

let rec split = function
  | []      -> Table.empty

  | [w]     ->
     Table.singleton { word=w ; min=length w }

  | w::x::t ->
     try
       let m = int_of_string x in
       Table.add { word=uppercase_ascii w ; min=m } (split t)
     with Failure _ ->
       let m = length w in
       Table.add { word=uppercase_ascii w ; min=m } (split (x::t))

let make_table table_as_string =
  split_on_char ' ' table_as_string
  |> clean_strings
  |> split

Finally, here is the function looking for a word :

let abbrev (table:Table.t) (w:string) : string =
  let w = uppercase_ascii w in
  try
    let e = Table.find { word=w ; min=length w } table in e.word
  with Not_found -> "*error*"

let rec check (table:Table.t) (inputs:string list) : unit =
  List.map (abbrev table) inputs
  |> List.iter (Printf.printf "%s ");
  print_newline ()
      
let main =
  let table = make_table table_as_string in
  let inputs = ["riG";"rePEAT";"copies";"put";"mo";"rest";"types";"fup.";"6";"poweRin"] in
  check table inputs;
  exit 0
Output:
Input:              riG       rePEAT    copies    put       mo        rest      types     fup.      6         poweRin
Output:             RIGHT     REPEAT    *error*   PUT       MOVE      RESTORE   *error*   *error*   *error*   POWERINPUT

Perl[edit]

Translation of: Raku
@c = (uc join ' ', qw<
add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
>) =~ /([a-zA-Z]+(?:\s+\d+)?)(?=\s+[a-zA-Z]|$)/g;

my %abr = ('' => '', ' ' => '');
for (@c) {
    ($w,$sl) = split ' ', $_;
    $ll = length($w);
    $sl = $ll unless $sl;
    $abr{substr($w,0,$sl)} = $w;
    map { $abr{substr($w, 0, $_)} = $w } $sl .. $ll;
}

$fmt = "%-10s";
$inp = sprintf $fmt, 'Input:';
$out = sprintf $fmt, 'Output:';
for $str ('', qw<riG rePEAT copies put mo rest types fup. 6 poweRin>) {
    $inp .= sprintf $fmt, $str;
    $out .= sprintf $fmt, $abr{uc $str} // '*error*';
}

print "$inp\n$out\n";
Output:
Input:              riG       rePEAT    copies    put       mo        rest      types     fup.      6         poweRin
Output:             RIGHT     REPEAT    *error*   PUT       MOVE      RESTORE   *error*   *error*   *error*   POWERINPUT

Phix[edit]

constant abbrtxt = """
   add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
""",
input = "riG   rePEAT copies  put mo   rest    types   fup.    6   poweRin"
 
function set_min_lengths(sequence a)
--
-- set default lengths and apply min lengths if present, eg ..."macro","merge","2",...
--  ==> {.."macro",5}} ==> {.."macro",5},{"merge",5}} ==> {.."macro",5},{"merge",2}}
-- ie both macro and merge get a default min length of 5, but the min length of merge 
--    is overwritten when the "2" is processed.
--
    sequence res = {}
    for i=1 to length(a) do
        string ai = a[i]
        if length(ai)=1 and ai>="1" and ai<="9" then
            res[$][2] = ai[1]-'0'
        else
            res = append(res,{ai,length(ai)})
        end if
    end for
    return res
end function
 
constant abbrevs = set_min_lengths(split(substitute(abbrtxt,"\n"," "),no_empty:=true))
constant inputs = split(input,no_empty:=true)
 
for i=1 to length(inputs) do
    string ii = inputs[i],
           res = "*error*"
    for j=1 to length(abbrevs) do
        {string aj, integer l} = abbrevs[j]
        if length(ii)>=l
        and match(ii,aj,case_insensitive:=true)==1 then
            res = upper(aj)
            exit
        end if
    end for
    puts(1,res&" ")
end for
puts(1,"\n")
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Python[edit]

Procedural[edit]

Works with: Python version 3.6
command_table_text = """add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"""

user_words = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"


def find_abbreviations_length(command_table_text):
    """ find the minimal abbreviation length for each word.
        a word that does not have minimum abbreviation length specified
        gets it's full lengths as the minimum.
    """
    command_table = dict()
    input_iter = iter(command_table_text.split())

    word = None
    try:
        while True:
            if word is None:
                word = next(input_iter)
            abbr_len = next(input_iter, len(word))
            try:
                command_table[word] = int(abbr_len)
                word = None
            except ValueError:
                command_table[word] = len(word)
                word = abbr_len
    except StopIteration:
        pass
    return command_table


def find_abbreviations(command_table):
    """ for each command insert all possible abbreviations"""
    abbreviations = dict()
    for command, min_abbr_len in command_table.items():
        for l in range(min_abbr_len, len(command)+1):
            abbr = command[:l].lower()
            abbreviations[abbr] = command.upper()
    return abbreviations


def parse_user_string(user_string, abbreviations):
    user_words = [word.lower() for word in user_string.split()]
    commands = [abbreviations.get(user_word, "*error*") for user_word in user_words]
    return " ".join(commands)


command_table = find_abbreviations_length(command_table_text)
abbreviations_table = find_abbreviations(command_table)

full_words = parse_user_string(user_words, abbreviations_table)

print("user words:", user_words)
print("full words:", full_words)
Output:
input:  ""
output: ""
input:  "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
output: "RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT"


Composition of pure functions[edit]

Works with: Python version 3.7
'''Simple abbreviations'''

from functools import reduce
import re


# withExpansions :: [(String, Int)] -> String -> String
def withExpansions(table):
    '''A string in which all words are either
       expanded (if they match abbreviations in
       a supplied table), or replaced with an
       '*error*' string.
    '''
    return lambda s: unwords(map(
        expanded(table), words(s)
    ))


# expanded :: [(String, Int)] -> String -> String
def expanded(table):
    '''An abbreviation (or error string) for
       a given word, based on a table of full
       strings and minimum abbreviation lengths.
    '''
    def expansion(k):
        u = k.upper()
        lng = len(k)

        def p(wn):
            w, n = wn
            return w.startswith(u) and lng >= n
        return find(p)(table) if k else Just(('', 0))

    return lambda s: maybe('*error*')(fst)(expansion(s))


# cmdsFromString :: String -> [(String, Int)]
def cmdsFromString(s):
    '''A simple rule-base consisting of a
       list of tuples [(
          upper case expansion string,
          minimum character count of abbreviation
       )],
       obtained by a parse of single input string.
    '''
    def go(a, x):
        xs, n = a
        return (xs, int(x)) if x.isdigit() else (
            ([(x.upper(), n)] + xs, 0)
        )
    return fst(reduce(
        go,
        reversed(re.split(r'\s+', s)),
        ([], 0)
    ))


# TEST -------------------------------------------------
def main():
    '''Tests of abbreviation expansions'''

    # table :: [(String, Int)]
    table = cmdsFromString(
        '''add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1
            Schange Cinsert 2  Clast 3 compress 4 copy 2 count 3 Coverlay 3
            cursor 3  delete 3 Cdelete 2  down 1  duplicate 3 xEdit 1 expand 3
            extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
            forward 2  get  help 1 hexType 4 input 1 powerInput 3  join 1
            split 2 spltJOIN load locate 1 Clocate 2 lowerCase 3 upperCase 3
            Lprefix 2  macro  merge 2 modify 3 move 2 msg  next 1 overlay 1
            parse preserve 4 purge 3 put putD query 1 quit read recover 3
            refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4
            rgtLEFT right 2 left 2  save  set  shift 2  si  sort  sos stack 3
            status 4 top  transfer 3  type 1  up 1'''
    )

    # tests :: [String]
    tests = [
        'riG   rePEAT copies  put mo   rest    types   fup.    6      poweRin',
        ''
    ]

    print(
        fTable(__doc__ + ':\n')(lambda s: "'" + s + "'")(
            lambda s: "\n\t'" + s + "'"
        )(withExpansions(table))(tests)
    )


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

# compose (<<<) :: (b -> c) -> (a -> b) -> a -> c
def compose(g):
    '''Right to left function composition.'''
    return lambda f: lambda x: g(f(x))


# Just :: a -> Maybe a
def Just(x):
    '''Constructor for an inhabited Maybe (option type) value.'''
    return {'type': 'Maybe', 'Nothing': False, 'Just': x}


# Nothing :: Maybe a
def Nothing():
    '''Constructor for an empty Maybe (option type) value.'''
    return {'type': 'Maybe', 'Nothing': True}


# find :: (a -> Bool) -> [a] -> Maybe a
def find(p):
    '''Just the first element in the list that matches p,
       or Nothing if no elements match.'''
    def go(xs):
        for x in xs:
            if p(x):
                return Just(x)
        return Nothing()
    return lambda xs: go(xs)


# fst :: (a, b) -> a
def fst(tpl):
    '''First member of a pair.'''
    return tpl[0]


# fTable :: String -> (a -> String)
#                  -> (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
    '''Heading -> x display function ->
                 fx display function ->
          f -> value list -> tabular string.'''
    def go(xShow, fxShow, f, xs):
        w = max(map(compose(len)(xShow), xs))
        return s + '\n' + '\n'.join([
            xShow(x).rjust(w, ' ') + (' -> ') + fxShow(f(x))
            for x in xs
        ])
    return lambda xShow: lambda fxShow: lambda f: lambda xs: go(
        xShow, fxShow, f, xs
    )


# maybe :: b -> (a -> b) -> Maybe a -> b
def maybe(v):
    '''Either the default value v, if m is Nothing,
       or the application of f to x,
       where m is Just(x).'''
    return lambda f: lambda m: v if m.get('Nothing') else (
        f(m.get('Just'))
    )


# unwords :: [String] -> String
def unwords(xs):
    '''A space-separated string derived from
       a list of words.'''
    return ' '.join(xs)


# words :: String -> [String]
def words(s):
    '''A list of words delimited by characters
       representing white space.'''
    return re.split(r'\s+', s)


# MAIN ---
if __name__ == '__main__':
    main()
Output:
Simple abbreviations:

'riG   rePEAT copies  put mo   rest    types   fup.    6      poweRin' -> 
    'RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT'
                                                                    '' -> 
    ''

Racket[edit]

#lang racket
(require srfi/13)

(define command-table #<<EOS
add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
EOS
  )

(define command/abbr-length-pairs
  (let loop ((cmd-len-list (string-split command-table)) (acc (list)))
    (match cmd-len-list
      ((list) (sort acc < #:key cdr))
      ((list-rest a (app string->number (and ad (not #f))) dd) (loop dd (cons (cons a ad) acc)))
      ((list-rest a d) (loop d (cons (cons a (string-length a)) acc))))))

(define (validate-word w)
  (or (let ((w-len (string-length w)))
        (for/first ((candidate command/abbr-length-pairs)
                    #:when (and (>= w-len (cdr candidate)) (string-prefix-ci? w (car candidate))))
          (string-upcase (car candidate))))
      "*error*"))

(define (validate-string s) (string-join (map validate-word (string-split s))))

(module+ main
  (define (debug-i/o s) (printf "input:  ~s~%output: ~s~%" s (validate-string s)))
  (debug-i/o "")
  (debug-i/o "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"))

(module+ test
  (require rackunit)
  (check-equal?
   (validate-string "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin")
   "RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT")
  (check-equal? (validate-string "") ""))
Output:
input:  ""
output: ""
input:  "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
output: "RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT"

Raku[edit]

(formerly Perl 6)

Works with: Rakudo version 2017.08

Demonstrate that inputting an empty string returns an empty string in addition to the required test input.

<
add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
> ~~ m:g/ (<.alpha>+) \s* (\d*) /;

my %abr = '' => '', |$/.map: {
    my $abbrv = .[0].Str.fc;
    |map { $abbrv.substr( 0, $_ ) => $abbrv.uc },
    +(.[1].Str || .[0].Str.chars) .. .[0].Str.chars;
};

sub abbr-simple ( $str ) { %abr{$str.trim.fc} // '*error*' }

# Testing
for 'riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin', '' -> $str {
    put ' Input: ', $str;
    put 'Output: ', join ' ', $str.words.map: &abbr-simple;
}
Output:
 Input: riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
Output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
 Input: 
Output: 

REXX[edit]

/*REXX program validates a user  "word"  against a  "command table"  with abbreviations.*/
parse arg uw                                     /*obtain optional arguments from the CL*/
if uw=''  then uw= 'riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin'
say 'user words: '   uw

@= 'add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3',
   'compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate',
   '3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2',
   'forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load',
   'locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2',
   'msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3',
   'refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left',
   '2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1'

say 'full words: '   validate(uw)                /*display the result(s) to the terminal*/
exit                                             /*stick a fork in it,  we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
validate: procedure expose @;  arg x;  upper @   /*ARG   capitalizes all the  X  words. */
          $=                                     /*initialize the return string to null.*/
             do j=1  to words(x);   _=word(x, j) /*obtain a word from the     X  list.  */
               do k=1  to words(@); a=word(@, k) /*get a legitmate command name from  @.*/
               L=word(@, k+1)                    /*··· and maybe get it's abbrev length.*/
               if datatype(L, 'W')  then k=k + 1       /*yuppers, it's an abbrev length.*/
                                    else L=length(a)   /*nope,  it can't be abbreviated.*/
               if abbrev(a, _, L)   then do; $=$ a;  iterate j;  end  /*is valid abbrev?*/
               end   /*k*/
             $=$ '*error*'                       /*processed the whole list, not valid. */
             end     /*j*/
          return strip($)                        /*elide the superfluous leading blank. */
output   when using the default input:
user words:  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
full words:  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Ruby[edit]

str = "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"

RE = /(?<word1>[a-zA-Z]+)\s+(?<word2>[a-zA-Z]+)/
str = str.upcase
# add missing wordsizes
2.times{ str.gsub!(RE){ [  $~[:word1], $~[:word1].size, $~[:word2] ].join(" ")} }

table = Hash[*str.split].transform_values(&:to_i)

test =  "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
ar = test.split.map do |w|
  (res = table.detect{|k,v| k.start_with?(w.upcase) && w.size >= v}) ? res[0] : "*error*"
end

puts ar.join(" ")
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Rust[edit]

Works with: Rust version 1.35.0

cargo clippy and cargo fmt run against it

use std::collections::HashMap;

// The plan here is to build a hashmap of all the commands keyed on the minimum number of
// letters than can be provided in the input to match. For each known command it will appear
// in a list of possible commands for a given string lengths. A command can therefore appear a
// number of times. For example, the command 'recover' has a minimum abbreviation length of 3.
// In the hashmap 'recover' will be stored behind keys for 3, 4, 5, 6 & 7 as any abbreviation of
// 'recover' from 3 until 7 letters inclusive can match. This way, once the length of the input
// string is known a subset of possible matches can be retrieved immediately and then checked.
//
fn main() {
    let command_table_string =
        "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
   compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
   3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
   forward 2  get  help 1 hexType 4  input_command 1 powerInput 3  join 1 split 2 spltJOIN load
   locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
   msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
   refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
   2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1";

    // Split up the command table string using the whitespace and set up an iterator
    // to run through it. We need the iterator to be peekable so that we can look ahead at
    // the next item.
    let mut iter = command_table_string.split_whitespace().peekable();

    let mut command_table = HashMap::new();

    // Attempt to take two items at a time from the command table string. These two items will be
    // the command string and the minimum length of the abbreviation. If there is no abbreviation length
    // then there is no number provided. As the second item might not be a number, so we need to peek at
    // it first. If it is a number we can use it as a key for the hashmap. If it is not a number then
    // we use the length of the first item instead because no abbreviations are available for the
    // word i.e. the whole word must be used. A while loop is used because we need to control iteration
    // and look ahead.
    //
    while let Some(command_string) = iter.next() {
        let command_string_length = command_string.len() as i32;

        let min_letter_match = match iter.peek() {
            Some(potential_number) => match potential_number.parse::<i32>() {
                Ok(number) => {
                    iter.next();
                    number
                }
                Err(_) => command_string_length,
            },
            None => break,
        };

        // The word must be stored for every valid abbreviation length.
        //
        for i in min_letter_match..=command_string_length {
            let cmd_list = command_table.entry(i).or_insert_with(Vec::new);
            cmd_list.push(command_string.to_uppercase());
        }
    }

    const ERROR_TEXT: &str = "*error*";

    let test_input_text = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin";

    let mut output_text = String::new();

    let mut iter = test_input_text.split_whitespace().peekable();

    // Run through each item in the input string, find the length of it
    // and then use this to fetch a list of possible matches.
    // A while loop is used because we need to look ahead in order to indentify
    // the last item and avoid adding an unnecessary space.
    //
    while let Some(input_command) = iter.next() {
        let input_command_length = input_command.len() as i32;

        let command_list = match command_table.get(&input_command_length) {
            Some(list) => list,
            None => {
                output_text.push_str(ERROR_TEXT);
                continue;
            }
        };

        let input_command_caps = input_command.to_uppercase();
        let matched_commands: Vec<&String> = command_list
            .iter()
            .filter(|command| command.starts_with(&input_command_caps))
            .collect();

        // Should either be 0 or 1 command found
        assert!(
            matched_commands.len() < 2,
            "Strange.. {:?}",
            matched_commands
        );

        match matched_commands.first() {
            Some(cmd) => output_text.push_str(cmd),
            None => output_text.push_str(ERROR_TEXT),
        }

        if iter.peek().is_some() {
            output_text.push(' ');
        }
    }

    println!("Input was: {}", test_input_text);
    println!("Output is: {}", output_text);

    let correct_output = "RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT";
    assert_eq!(output_text, correct_output)
}
Output:
Input was: riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
Output is: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Scala[edit]

object Main extends App {
    implicit class StrOps(i: String) {
        def isAbbreviationOf(target: String, targetMinLength: Int): Boolean = {
            @scala.annotation.tailrec
            def checkPAsPrefixOfM(p: List[Char], m: List[Char]): Boolean = (p, m) match {
                case (Nil, _) => true //prefix empty
                case (_, Nil) => false //main string empty
                case (ph :: pt, mh :: mt) if ph.toUpper == mh.toUpper => checkPAsPrefixOfM(pt, mt) //case insensitive match of head characters
                case _ => false
            }
            i.length >= targetMinLength && checkPAsPrefixOfM(i.toList, target.toList)
        }
    }

    val commands = """
         add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
         compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
         3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
         forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
         locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
         msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
         refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
         2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1
      """.stripMargin.replace("\n", " ").trim.split(" ")

    val commandWithMinLengths = commands.sliding(2, 1)
                                       .filter{ window => 
                                           window.length > 1 && Try(window(0).toInt).toOption.isEmpty
                                       }
                                       .map{ w => 
                                           (
                                               w(0), 
                                               Try(w(1).toInt).toOption.getOrElse(0)
                                           )
                                       }
                                       .toList

    val input = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin".split(" ").filter(!_.isEmpty)

    val resultLine = input.map{ i =>
        commandWithMinLengths.find{case (c, l) => i.isAbbreviationOf(c, l)}.map(_._1.toUpperCase).getOrElse("*error*")
    }.mkString(" ")

    println(resultLine)
}
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

SNOBOL4[edit]

* Program: abbr_simple.sbl
* To run: sbl abbr_simple.sbl
* Description: Abbreviations, simple
* Comment: Tested using the Spitbol for Linux version of SNOBOL4

	commands =
+   "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 "
+   "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate "
+   "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 "
+   "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load "
+   "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 "
+   "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 "
+   "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left "
+   "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1 "

	commands = replace(commands,&lcase,&ucase)
	numerals = '0123456789'


* Function filltable will fill the command abbreviations table
	define("filltable(s,n)slen,i")
		ct = table(300, ,"*error*") :f(errr);* command abbreviations table
	:(filltable_end)
filltable
	slen = size(s)
	ct[s] = s
	eq(n,slen) :s(filltable3)
	i = n - 1
filltable2
	i = lt(i,slen - 1) i + 1 :f(filltable3)
	ct[substr(s,1,i)] = s
	:(filltable2)
filltable3
	filltable = ""
	:(return)
filltable_end


x0
* Populate command abbreviations table
	commands ? (span(' ') | "") breakx(&ucase) span(&ucase) . c
+		span(' ') (span(numerals) | "") . ablen = "" :f(x1)
	ablen = ident(ablen) size(c)
	ret = filltable(c,ablen)
    :(x0)
x1
* Process user string
	userstring = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
	output = "Original user string:"
	output = userstring
	userstring = replace(userstring,&lcase,&ucase)
x2
	userstring ? (span(' ') | "") (break(' ') | (len(1) rem)) . c = "" :f(x3)
	user_commands = (gt(size(user_commands),0) user_commands ' ' ct[c], ct[c])
	:(x2)
x3
	output = ""
	output = "User string with abbreviations expanded:"
	output = user_commands

END
Output:
Original user string:
riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin

User string with abbreviations expanded:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Tcl[edit]

proc appendCmd {word} {
  # Procedure to append the correct command from the global list ::cmds
  # for the word given as parameter to the global list ::result.
  # If a matching word has been found and appended to ::result, this procedure
  # behaves like a "continue" statement, causing the loop containing it to
  # jump over the rest of the body.
  set candidates [lsearch -inline -all -nocase -glob $::cmds "${word}*"]
  foreach cand $candidates {
    if {[string length $word] >= $::minLen($cand)} {
      lappend ::result [string toupper $cand]
      return -code continue
    }
  }
}

set cmds {Add ALTer  BAckup Bottom  CAppend Change SCHANGE  CInsert CLAst COMPress COpy
   COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find
   NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput
   Join SPlit SPLTJOIN  LOAD  Locate CLocate  LOWercase UPPercase  LPrefix MACRO
   MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD  Query  QUIT
   READ  RECover REFRESH RENum REPeat  Replace CReplace  RESet  RESTore  RGTLEFT
   RIght LEft  SAVE  SET SHift SI  SORT  SOS  STAck STATus  TOP TRAnsfer Type Up}

# Find the minimum lengths necessary for each command.
foreach c $cmds {
  regexp {^[A-Z]+} $c match
  set minLen($c) [string length $match]
}

set words {riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin}
set result {}

foreach w $words {
  appendCmd $w
  lappend result *error*
}

puts "user words: $words"
puts $result
Output:
./abbreviations_simple.tcl

user words: riG rePEAT copies put mo rest types fup. 6 poweRin RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

VBA[edit]

Private Function ValidateUserWords(userstring As String) As String
    Dim s As String
    Dim user_words() As String
    Dim command_table As Scripting.Dictionary
    Set command_table = New Scripting.Dictionary
    Dim abbreviations As Scripting.Dictionary
    Set abbreviations = New Scripting.Dictionary
    abbreviations.CompareMode = TextCompare
    Dim commandtable() As String
    Dim commands As String
    s = s & "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 "
    s = s & "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate "
    s = s & "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 "
    s = s & "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load "
    s = s & "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 "
    s = s & "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 "
    s = s & "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left "
    s = s & "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1 "
    commandtable = Split(s, " ")
    Dim i As Integer, word As Variant, number As Integer
    For i = LBound(commandtable) To UBound(commandtable)
        word = commandtable(i)
        If Len(word) > 0 Then
            i = i + 1
            Do While Len(commandtable(i)) = 0: i = i + 1: Loop
            number = Val(commandtable(i))
            If number > 0 Then
                command_table.Add Key:=word, Item:=number
            Else
                command_table.Add Key:=word, Item:=Len(word)
                i = i - 1
            End If
        End If
    Next i
    For Each word In command_table
        For i = command_table(word) To Len(word)
            On Error Resume Next
            abbreviations.Add Key:=Left(word, i), Item:=UCase(word)
        Next i
    Next word
    user_words() = Split(userstring, " ")
    For Each word In user_words
        If Len(word) > 0 Then
            If abbreviations.exists(word) Then
                commands = commands & abbreviations(word) & " "
            Else
                commands = commands & "*error* "
            End If
        End If
    Next word
    ValidateUserWords = commands
End Function
Public Sub program()
    Dim guserstring As String
    guserstring = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
    Debug.Print "user words:", guserstring
    Debug.Print "full words:", ValidateUserWords(guserstring)
End Sub
Output:
user words:   riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin

full words: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

VBScript[edit]

option explicit

function iif(c,t,f) if c then iif=t else iif=f end if: end function
function usrin(pr)  wscript.stdout.write vbcrlf &pr &": ":usrin= wscript.stdin.readline:end function  

sub do_abbrev
  dim j, sm,n,n0,a
  for each j in m
    sm=trim(lcase(j.submatches(0)))
    n0=iif (j.submatches(1)="",1,  j.submatches(1)) 
    n=1
    do 
      a=left(sm,n) 
      if not d.exists(a)  then 
        d.add a,sm
      else 
        if len(a)=len(sm) then 
           d(a)=sm
        elseif len(d(a))>len(a) then 
          d(a)=null
        end if  
      end if  
      n=n+1
    loop until n>len(sm)
  next
end sub 
'output sorted

sub display
  dim d2,k,j,kk,mm
  set d2=createobject("Scripting.dictionary")
  for each k in d
      kk=d(k)
    if not isnull(kk) then  
     if not d2.exists(kk) then
       d2.add kk,k
     else
       d2(kk)= d2(kk) & " " & k
     end if      
     end if
  next
  for each j in m
    mm=trim(lcase(j.submatches(0)))
    wscript.echo left(mm&space(15),15),d2(mm)
  next
  wscript.echo 
  set d2=nothing
end sub

sub test 
  wscript.echo vbcrlf&"test:" 
  dim a,i,k,s1
  do
    s1= lcase(usrin("Command?"))
    if trim(s1)="" then wscript.quit
    a=split(trim(s1)," ")
    for i=0 to ubound(a)
      if a(i)<>"" then
        wscript.stdout.write iif (d.exists(a(i)), ucase(d(a(i)))," **ERROR**")& " "
      end if  
    next
  loop  
end sub

'main program
dim s:s=_
   "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 "&_
   "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate "&_
   "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 "&_
   "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load "&_
   "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 "&_
   "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 "&_
   "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left "&_
   "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1 "
dim m,d 

'use regexp to separate input
with new regexp
 .pattern="([a-z]+?)\s+(\d?)"
 .global=true
 .ignorecase=true
 set m=.execute(s)
end with 

set d=createobject("Scripting.dictionary")
do_abbrev
'display
test
Output:
Command?:  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
RIGHT REPEAT  **ERROR** PUT  RESTORE  **ERROR**  **ERROR**  **ERROR** POWERINPUT

Vlang[edit]

Translation of: Go
import encoding.utf8
import strconv
fn read_table(table string) ([]string, []int) {
    fields := table.fields()
    mut commands := []string{}
    mut min_lens := []int{}
 
    for i, max := 0, fields.len; i < max; {
        cmd := fields[i]
        mut cmd_len := cmd.len
        i++
 
        if i < max {
            num := strconv.atoi(fields[i]) or {-1}
            if 1 <= num && num < cmd_len {
                cmd_len = num
                i++
            }
        }
        commands << cmd
        min_lens << cmd_len
    }
    return commands, min_lens
}
 
fn validate_commands(commands []string, min_lens []int, words []string) []string {
    mut results := []string{}
    for word in words {
        mut match_found := false
        wlen := word.len
        for i, command in commands {
            if min_lens[i] == 0 || wlen < min_lens[i] || wlen > command.len {
                continue
            }
            c := utf8.to_upper(command)
            w := utf8.to_upper(word)
            if c.index(w) or {-1} == 0 {
                results << c
                match_found = true
                break
            }
        }
        if !match_found {
            results << "*error*"
        }
    }
    return results
}
 
fn print_results(words []string, results []string) {
    println("user words:\t${words.join("\t")}")
    println("full words:\t${results.join("\t")}")
}
 
fn main() {
    table := "" +
    "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 " +
    "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate " +
    "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 " +
    "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load " +
    "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 " +
    "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 " +
    "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left " +
    "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1 "
     
    sentence := "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
     
    commands, min_lens := read_table(table)
    words := sentence.fields()
     
    results := validate_commands(commands, min_lens, words)
     
    print_results(words, results)
}
Output:
user words:  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin    
full words:  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Wren[edit]

Library: Wren-fmt
Library: Wren-str

Based on an older version of the Go entry.

import "/fmt" for Fmt
import "/str" for Str

var table =
    "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3 " +
    "compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate " +
    "3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 " +
    "forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load " +
    "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2 " +
    "msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3 " +
    "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left " +
    "2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"
 
var validate = Fn.new { |commands, words, minLens|
    var results = []
    if (words.count == 0) return results
    for (word in words) {
        var matchFound = false
        var wlen = word.count
        for (i in 0...commands.count) {
            var command = commands[i]
            if (minLens[i] != 0 && wlen >= minLens[i] && wlen <= command.count) {
                var c = Str.upper(command)
                var w = Str.upper(word)
                if (c.startsWith(w)) {
                    results.add(c)
                    matchFound = true
                    break
                }
            }
        }
        if (!matchFound) results.add("*error*")
    }
    return results
}

var splits = table.split(" ")
// get rid of empty entries
for (i in splits.count-1..0) if (splits[i] == "") splits.removeAt(i)
var slen = splits.count
var commands = []
var minLens = []
var i = 0
while (true) {
    commands.add(splits[i])
    var len = splits[i].count
    if (i == slen - 1) {
        minLens.add(len)
        break
    }
    i = i + 1
    var num = Num.fromString(splits[i])
    if (num != null) {
        minLens.add( (num < len) ? num : len )
        i = i + 1
        if (i == slen) break
    } else minLens.add(len)
}
var sentence = "riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin"
var words = sentence.split(" ")
// get rid of empty entries
for (i in words.count-1..0) if (words[i] == "") words.removeAt(i)
var results = validate.call(commands, words, minLens)
System.write("user words:  ")
for (j in 0...words.count) {
    System.write("%(Fmt.s(-results[j].count, words[j])) ")
}
System.write("\nfull words:  ")
System.print(results.join(" "))
Output:
user words:  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin    
full words:  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

Yabasic[edit]

c$ = "add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2 Clast 3" 
c$ = c$ + " compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate"
c$ = c$ + " 3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2" 
c$ = c$ + " forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load" 
c$ = c$ + " locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2" 
c$ = c$ + " msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3" 
c$ = c$ + " refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left" 
c$ = c$ + " 2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"

c$ = upper$(c$)
 
dim chunk$(1)

n = token(c$, chunk$())

dim lonc(n)

for i = 1 to n - 1
    v = val(chunk$(i + 1))
    if v then
        lonc(i) = v
        chunk$(i + 1) = ""
    else
        lonc(i) = len(chunk$(i))
    end if 
next

inp$ = "riG   rePEAT copies   put mo   rest    types   fup.    6       poweRin"
inp$ = upper$(inp$) 

dim w$(1)

x = token(inp$, w$())

dim lonw(x)

for i = 1 to x : lonw(i) = len(w$(i)) : next

for j = 1 to x
    p$ = ""
    for i = 1 to n
        lc$ = left$(chunk$(i), lonw(j)) : lw$ = w$(j)
        if (lw$ = lc$) and (lonc(i) <= lonw(j))  p$ = chunk$(i) : break
    next
    if p$ = "" p$ = "*error*"
    r$ = r$ + " " + p$
next

print r$
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

zkl[edit]

commands:=Data(0,String,	// "add\01\0alter\0..."
#<<<
"add 1  alter 3  backup 2  bottom 1  Cappend 2  change 1  Schange  Cinsert 2  Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3  delete 3 Cdelete 2  down 1  duplicate
3 xEdit 1 expand 3 extract 3  find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
forward 2  get  help 1 hexType 4  input 1 powerInput 3  join 1 split 2 spltJOIN load
locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2  macro  merge 2 modify 3 move 2
msg  next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit  read recover 3
refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
2  save  set  shift 2  si  sort  sos  stack 3 status 4 top  transfer 3  type 1  up 1"
.toUpper().split());
#<<<

var szs=Dictionary(); // [<index>:<length> ...]
n:=0; while(n<commands.len()){
   cmd,nc := commands.readString(n), n + cmd.len() + 1;
   len:=commands.readString(nc);
   if(len.matches("[0-9]*")){ szs[n]=len.toInt(); n=nc+len.len()+1 }
   else			    { szs[n]=cmd.len();   n=nc; }
}

testText:="riG   rePEAT copies  put mo   rest    types "
          "   fup.    6       poweRin";

testText.split().apply('wrap(w){ 
   w=w.toUpper(); n:=0;
   while(True){  // check for length requirement and, if there, verify
      n=commands.find(w,n);
      if(Void==n) return("*error*");	// end of loop if no match
      c:=commands.readString(n);
      if(w.len()>=szs.find(n,99999)) return(c);
      n+=c.len();
   }
}).concat(" ").println();
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT