Abbreviations, easy: Difference between revisions
No edit summary |
(Ada version) |
||
Line 588: | Line 588: | ||
pi@debian-buster-64:~/asm64/rosetta/asm9 $ |
pi@debian-buster-64:~/asm64/rosetta/asm9 $ |
||
</pre> |
</pre> |
||
=={{header|Ada}}== |
|||
<lang Ada>with Ada.Characters.Handling; |
|||
with Ada.Containers.Indefinite_Vectors; |
|||
with Ada.Strings.Fixed; |
|||
with Ada.Strings.Maps.Constants; |
|||
with Ada.Text_IO; |
|||
procedure Abbreviations_Easy is |
|||
package Command_Vectors |
|||
is new Ada.Containers.Indefinite_Vectors (Index_Type => Positive, |
|||
Element_Type => String); |
|||
use Command_Vectors; |
|||
Commands : Vector; |
|||
procedure Append (Word_List : String) is |
|||
use Ada.Strings; |
|||
First : Positive := Word_List'First; |
|||
Last : Natural; |
|||
begin |
|||
loop |
|||
Fixed.Find_Token (Word_List, |
|||
Set => Maps.Constants.Letter_Set, |
|||
From => First, |
|||
Test => Inside, |
|||
First => First, |
|||
Last => Last); |
|||
exit when Last = 0; |
|||
Commands.Append (Word_List (First .. Last)); |
|||
exit when Last = Word_List'Last; |
|||
First := Last + 1; |
|||
end loop; |
|||
end Append; |
|||
function Match (Word : String) return String is |
|||
use Ada.Strings; |
|||
use Ada.Characters.Handling; |
|||
Upper_Word : constant String := To_Upper (Word); |
|||
Prefix_First : Positive; |
|||
Prefix_Last : Natural; |
|||
begin |
|||
if Word = "" then |
|||
return ""; |
|||
end if; |
|||
for Command of Commands loop |
|||
Fixed.Find_Token (Command, Maps.Constants.Upper_Set, Inside, |
|||
Prefix_First, Prefix_Last); |
|||
declare |
|||
Upper_Prefix : constant String := Command (Prefix_First .. Prefix_Last); |
|||
Upper_Command : constant String := To_Upper (Command); |
|||
Valid_Length : constant Boolean := Word'Length >= Upper_Prefix'Length; |
|||
Match_Length : constant Natural := Natural'Min (Word'Length, |
|||
Command'Length); |
|||
Valid_Match : constant Boolean |
|||
:= Fixed.Head (Upper_Word, Upper_Word'Length) |
|||
= Fixed.Head (Upper_Command, Upper_Word'Length); |
|||
begin |
|||
if Valid_Length and Valid_Match then |
|||
return Upper_Command; |
|||
end if; |
|||
end; |
|||
end loop; |
|||
return "*error*"; |
|||
end Match; |
|||
procedure Put_Match (To : String) is |
|||
use Ada.Text_IO; |
|||
M : constant String := Match (To); |
|||
begin |
|||
Put ("Match to '"); Put (To); |
|||
Put ("' is '"); Put (M); |
|||
Put_Line ("'"); |
|||
end Put_Match; |
|||
procedure A (Item : String) renames Append; |
|||
begin |
|||
A ("Add ALTer BAckup Bottom CAppend Change SCHANGE CInsert CLAst COMPress COpy"); |
|||
A ("COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find"); |
|||
A ("NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput"); |
|||
A ("Join SPlit SPLTJOIN LOAD Locate CLocate LOWercase UPPercase LPrefix MACRO"); |
|||
A ("MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD Query QUIT"); |
|||
A ("READ RECover REFRESH RENum REPeat Replace CReplace RESet RESTore RGTLEFT"); |
|||
A ("RIght LEft SAVE SET SHift SI SORT SOS STAck STATus TOP TRAnsfer Type Up"); |
|||
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 (""); |
|||
Put_Match ("o"); |
|||
end Abbreviations_Easy;</lang> |
|||
=={{header|ALGOL 68}}== |
=={{header|ALGOL 68}}== |
Revision as of 12:12, 15 March 2022
You are encouraged to solve this task according to the task description, using any language you may know.
This task is an easier (to code) variant of the Rosetta Code task: Abbreviations, simple.
For this task, the following command table will be used:
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
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 valid abbreviation is a word that has:
- at least the minimum length of the number of capital letters of the word 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
- AL, ALF, ALTERS, TER, and A aren't valid abbreviations of ALTer
- The number of capital letters in ALTer indicates that any abbreviation for ALTer must be at least three letters
- 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
- if there isn't any lowercase letters in the word in the command table, 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
- Metrics
- Counting
- Word frequency
- Letter frequency
- Jewels and stones
- I before E except after C
- Bioinformatics/base count
- Count occurrences of a substring
- Count how many vowels and consonants occur in a string
- Remove/replace
- XXXX redacted
- Conjugate a Latin verb
- Remove vowels from a string
- String interpolation (included)
- Strip block comments
- Strip comments from a string
- Strip a set of characters from a string
- Strip whitespace from a string -- top and tail
- Strip control codes and extended characters from a string
- Anagrams/Derangements/shuffling
- Word wheel
- ABC problem
- Sattolo cycle
- Knuth shuffle
- Ordered words
- Superpermutation minimisation
- Textonyms (using a phone text pad)
- Anagrams
- Anagrams/Deranged anagrams
- Permutations/Derangements
- Find/Search/Determine
- ABC words
- Odd words
- Word ladder
- Semordnilap
- Word search
- Wordiff (game)
- String matching
- Tea cup rim text
- Alternade words
- Changeable words
- State name puzzle
- String comparison
- Unique characters
- Unique characters in each string
- Extract file extension
- Levenshtein distance
- Palindrome detection
- Common list elements
- Longest common suffix
- Longest common prefix
- Compare a list of strings
- Longest common substring
- Find common directory path
- Words from neighbour ones
- Change e letters to i in words
- Non-continuous subsequences
- Longest common subsequence
- Longest palindromic substrings
- Longest increasing subsequence
- Words containing "the" substring
- Sum of the digits of n is substring of n
- Determine if a string is numeric
- Determine if a string is collapsible
- Determine if a string is squeezable
- Determine if a string has all unique characters
- Determine if a string has all the same characters
- Longest substrings without repeating characters
- Find words which contains all the vowels
- Find words which contains most consonants
- Find words which contains more than 3 vowels
- Find words which first and last three letters are equals
- Find words which odd letters are consonants and even letters are vowels or vice_versa
- Formatting
- Substring
- Rep-string
- Word wrap
- String case
- Align columns
- Literals/String
- Repeat a string
- Brace expansion
- Brace expansion using ranges
- Reverse a string
- Phrase reversals
- Comma quibbling
- Special characters
- String concatenation
- Substring/Top and tail
- Commatizing numbers
- Reverse words in a string
- Suffixation of decimal numbers
- Long literals, with continuations
- Numerical and alphabetical suffixes
- Abbreviations, easy
- Abbreviations, simple
- Abbreviations, automatic
- Song lyrics/poems/Mad Libs/phrases
- Mad Libs
- Magic 8-ball
- 99 Bottles of Beer
- The Name Game (a song)
- The Old lady swallowed a fly
- The Twelve Days of Christmas
- Tokenize
- Text between
- Tokenize a string
- Word break problem
- Tokenize a string with escaping
- Split a character string based on change of character
- Sequences
11l
<lang 11l>V command_table_text = |‘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’
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 by counting capital letters. a word that does not have capital letters gets it's full length as the minimum. ’ [String = Int] command_table L(word) command_table_text.split((‘ ’, "\n"), group_delimiters' 1B) V abbr_len = sum(word.filter(c -> c.is_uppercase()).map(c -> 1)) I abbr_len == 0 abbr_len = word.len command_table[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)</lang>
- 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
<lang AArch64 Assembly> /* ARM assembly AARCH64 Raspberry PI 3B */ /* program abbrEasy64.s */ /* store list of command in a file */ /* and run the program abbrEasy64 command.file */
/*******************************************/ /* Constantes file */ /*******************************************/ /* for this file see task include a file in language AArch64 assembly*/ .include "../includeConstantesARM64.inc"
.equ BUFFERSIZE, 1000 .equ NBMAXIELEMENTS, 100
/*********************************/ /* Initialized data */ /*********************************/ .data szMessTitre: .asciz "Nom du fichier : " szCarriageReturn: .asciz "\n" szMessErreur: .asciz "Error detected.\n" szMessErrBuffer: .asciz "buffer size too less !!" szMessErrorAbr: .asciz "*error*" szMessInput: .asciz "Enter command (or quit to stop) : " szCmdQuit: .asciz "QUIT" szValTest1: .asciz "Quit" szValTest2: .asciz "Rep" /*********************************/ /* UnInitialized data */ /*********************************/ .bss .align 4 sZoneConv: .skip 24 qAdrFicName: .skip 8 iTabAdrCmd: .skip 8 * 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 ldr x0,qAdrsBuffer ldr x1,qAdriTabAdrCmd bl controlCommand // control text command mov x2,x0 bl affichageMess ldr x0,qAdrszCarriageReturn bl affichageMess mov x0,x2 ldr x1,qAdrszCmdQuit // command quit ? bl comparStrings cmp x0,#0 beq 100f // yes -> end b 1b // else 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 qAdrszCmdQuit: .quad szCmdQuit /******************************************************************/ /* 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 bl computeLength // length input command mov x4,x0 // save length input mov x2,#0 // indice mov x3,#0 // find counter
1: // loop search command in table
ldr x1,[x9,x2,lsl #3] // load a item cmp x1,#0 // end ? beq 5f mov x0,x8 bl comparStringSpe // cmp x0,#0 // no found other search beq 4f mov x6,#0 mov x5,#0
2: // loop count capital letters
ldrb w0,[x1,x6] cmp x0,#0 beq 3f tst x0,#0x20 // capital letter ? cinc x5,x5,eq add x6,x6,#1 b 2b
3:
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
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
// OK mov x4,#0x20 // 5 bit to 1 mov x2,#0
6:
ldrb w3,[x7,x2] cmp x3,#0 beq 7f bic x3,x3,x4 // convert to capital letter strb w3,[x8,x2] add x2,x2,#1 b 6b
7:
strb w3,[x8,x2] // store zéro final 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 x4,x3,#0x20 // convert capital letter ldrb w5,[x1,x2] // table orr x6,x5,#0x20 // convert capital letter cmp x4,x6 bne 2f cmp x3,#0 beq 3f add x2,x2,#1 b 1b
2:
cmp x3,#0 // fist letters Ok beq 3f 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:
stp x1,lr,[sp,-16]! // save registres stp x2,x3,[sp,-16]! // save registres mov x1,#0
1:
ldrb w2,[x0,x1] cmp x2,#0 // end ? beq 2f 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 x2,#0 // string buffer indice mov x4,x1 // start string mov x5,#0 // string index //vidregtit debextrac
1:
ldrb w3,[x6,x2] cmp x3,#0 beq 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 x3,#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 str x4,[x7,x5,lsl #3] add x5,x5,#1
5:
ldrb w3,[x6,x2] cmp x3,#0 beq 100f cmp x3,#' ' cinc x2,x2,eq //addeq x2,x2,#1 beq 5b 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 mov x2,x0 mov x1,#0
1:
ldr x0,[x2,x1,lsl #3] cmp x0,#0 beq 100f bl affichageMess ldr x0,qAdrszCarriageReturn bl affichageMess add x1,x1,#1 b 1b
100:
ldp x2,x3,[sp],16 // restaur des 2 registres ldp x1,lr,[sp],16 // restaur des 2 registres ret
/************************************/ /* Strings case sensitive comparisons */ /************************************/ /* x0 et x1 contains the address of strings */ /* return 0 in x0 if equals */ /* return -1 if string x0 < string x1 */ /* return 1 if string x0 > string x1 */ comparStrings:
stp x1,lr,[sp,-16]! // save registres stp x2,x3,[sp,-16]! // save registres stp x4,x5,[sp,-16]! // save registres mov x2,#0 // counter
1:
ldrb w3,[x0,x2] // byte string 1 ldrb w4,[x1,x2] // byte string 2 cmp x3,x4 blt 2f bgt 3f cmp x3,#0 // 0 end string beq 4f // end string add x2,x2,#1 // else add 1 in counter b 1b // and loop
2:
mov x0,#-1 // small b 100f
3:
mov x0,#1 // greather b 100f
4:
mov x0,#0 // equal
100:
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
/********************************************************/ /* File Include fonctions */ /********************************************************/ /* for this file see task include a file in language AArch64 assembly */ .include "../includeARM64.inc" </lang>
Enter command (or quit to stop) : riG RIGHT Enter command (or quit to stop) : rePEAT REPEAT Enter command (or quit to stop) : copies *error* Enter command (or quit to stop) : put PUT Enter command (or quit to stop) : mo MOVE Enter command (or quit to stop) : rest RESTORE Enter command (or quit to stop) : types *error* Enter command (or quit to stop) : fup. *error* Enter command (or quit to stop) : 6 *error* Enter command (or quit to stop) : poweRin POWERINPUT Enter command (or quit to stop) : quit QUIT pi@debian-buster-64:~/asm64/rosetta/asm9 $
Ada
<lang Ada>with Ada.Characters.Handling; with Ada.Containers.Indefinite_Vectors; with Ada.Strings.Fixed; with Ada.Strings.Maps.Constants; with Ada.Text_IO;
procedure Abbreviations_Easy is
package Command_Vectors is new Ada.Containers.Indefinite_Vectors (Index_Type => Positive, Element_Type => String); use Command_Vectors;
Commands : Vector;
procedure Append (Word_List : String) is use Ada.Strings; First : Positive := Word_List'First; Last : Natural; begin loop Fixed.Find_Token (Word_List, Set => Maps.Constants.Letter_Set, From => First, Test => Inside, First => First, Last => Last); exit when Last = 0; Commands.Append (Word_List (First .. Last)); exit when Last = Word_List'Last; First := Last + 1; end loop; end Append;
function Match (Word : String) return String is use Ada.Strings; use Ada.Characters.Handling; Upper_Word : constant String := To_Upper (Word); Prefix_First : Positive; Prefix_Last : Natural; begin if Word = "" then return ""; end if;
for Command of Commands loop Fixed.Find_Token (Command, Maps.Constants.Upper_Set, Inside, Prefix_First, Prefix_Last); declare Upper_Prefix : constant String := Command (Prefix_First .. Prefix_Last); Upper_Command : constant String := To_Upper (Command); Valid_Length : constant Boolean := Word'Length >= Upper_Prefix'Length; Match_Length : constant Natural := Natural'Min (Word'Length, Command'Length); Valid_Match : constant Boolean := Fixed.Head (Upper_Word, Upper_Word'Length) = Fixed.Head (Upper_Command, Upper_Word'Length); begin if Valid_Length and Valid_Match then return Upper_Command; end if; end; end loop; return "*error*"; end Match;
procedure Put_Match (To : String) is use Ada.Text_IO; M : constant String := Match (To); begin Put ("Match to '"); Put (To); Put ("' is '"); Put (M); Put_Line ("'"); end Put_Match;
procedure A (Item : String) renames Append;
begin
A ("Add ALTer BAckup Bottom CAppend Change SCHANGE CInsert CLAst COMPress COpy"); A ("COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find"); A ("NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput"); A ("Join SPlit SPLTJOIN LOAD Locate CLocate LOWercase UPPercase LPrefix MACRO"); A ("MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD Query QUIT"); A ("READ RECover REFRESH RENum REPeat Replace CReplace RESet RESTore RGTLEFT"); A ("RIght LEft SAVE SET SHift SI SORT SOS STAck STATus TOP TRAnsfer Type Up");
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 (""); Put_Match ("o");
end Abbreviations_Easy;</lang>
ALGOL 68
Uses Algol 68G specific is lower and to upper procedures. Does not use a hash table. <lang algol68># "Easy" abbreviations #
- table of "commands" - upper-case indicates the mminimum abbreviation #
STRING command table = "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";
- 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 the minimum abbreviation length of command #
OP MINABLENGTH = ( STRING command )INT:
BEGIN INT ab min := LWB command; WHILE IF ab min > UPB command THEN FALSE ELSE is upper( command[ ab min ] ) FI DO ab min +:= 1 OD; ab min - LWB command END # MINABLENGTH # ;
- searches for word in command table and returns the full command #
- matching the possible abbreviation or *error* if there is no match #
PRIO EXPAND = 1; OP EXPAND = ( STRING command table, word )STRING:
IF word = "" THEN # empty word # "" ELSE # non-empty word # INT word len = ( UPB word + 1 ) - LWB word; STRING upper word := TOUPPER word; STRING result := "*error*"; INT pos := LWB command table; WHILE STRING command := pos NEXTWORD command table; IF command = "" THEN # end of command table # FALSE ELIF word len < MINABLENGTH command OR word len > ( ( UPB command + 1 ) - LWB command ) THEN # word is too short or too long - try the next command # TRUE ELIF upper word = TOUPPER command[ LWB command : ( LWB command - 1 ) + word len ] THEN # found the command # result := TOUPPER 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, command table )VOID:
BEGIN STRING results := "", separator := ""; INT pos := LWB words; WHILE STRING word = pos NEXTWORD words; word /= "" DO results +:= separator + ( command table EXPAND word ); separator := " " OD; print( ( "Input: ", words, newline ) ); print( ( "Output: ", results, newline ) ) END # test expand # ;
- task test cases #
test expand( "riG rePEAT copies put mo rest types fup. 6 poweRin", command table ); test expand( "", command table )</lang>
- 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:
ARM Assembly
Correction program 15/11/2020
<lang ARM Assembly> /* ARM assembly Raspberry PI */ /* program abbrEasy.s */ /* store list of command in a file */ /* and run the program abbrEasy 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 SIZE, 4 .equ NBBOX, SIZE * SIZE .equ BUFFERSIZE, 1000 .equ NBMAXIELEMENTS, 100
/*********************************/ /* Initialized data */ /*********************************/ .data szMessTitre: .asciz "Nom du fichier : " szCarriageReturn: .asciz "\n" szMessErreur: .asciz "Error detected.\n" szMessErrBuffer: .asciz "buffer size too less !!" szMessErrorAbr: .asciz "*error*" szMessInput: .asciz "Enter command (or quit to stop) : " szCmdQuit: .asciz "QUIT" szValTest1: .asciz "Quit" szValTest2: .asciz "Rep" /*********************************/ /* UnInitialized data */ /*********************************/ .bss .align 4 sZoneConv: .skip 24 iAdrFicName: .skip 4 iTabAdrCmd: .skip 4 * 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 ldr r0,iAdrsBuffer ldr r1,iAdriTabAdrCmd bl controlCommand @ control text command mov r2,r0 bl affichageMess ldr r0,iAdrszCarriageReturn bl affichageMess mov r0,r2 ldr r1,iAdrszCmdQuit @ command quit ? bl comparStrings cmp r0,#0 beq 100f @ yes -> end b 1b @ else 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 iAdrszCmdQuit: .int szCmdQuit /******************************************************************/ /* 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 bl computeLength @ length input command mov r4,r0 @ save length input mov r2,#0 @ indice mov r3,#0 @ find counter
1:
mov r0,r8 ldr r1,[r9,r2,lsl #2] @ load a item cmp r1,#0 @ end ? beq 5f bl comparStringSpe @ cmp r0,#0 @ no found other search beq 4f mov r6,#0 mov r5,#0
2: @ loop count capital letters
ldrb r0,[r1,r6] cmp r0,#0 beq 3f tst r0,#0x20 @ capital letter ? addeq r5,r5,#1 add r6,r6,#1 b 2b
3:
cmp r4,r5 @ input < command capital letters blt 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 r2,#0 @ string buffer indice mov r4,r1 @ start string mov r5,#0 @ string index //vidregtit debextrac
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 str r4,[r7,r5,lsl #2] add r5,#1
5:
ldrb r3,[r6,r2] cmp r3,#0 beq 100f cmp r3,#' ' addeq r2,r2,#1 beq 5b 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-r8,lr} @ save registers mov r5,r0 mov r1,#0
1:
ldr r0,[r5,r1,lsl #2] cmp r0,#0 beq 100f bl affichageMess ldr r0,iAdrszCarriageReturn bl affichageMess add r1,r1,#1 b 1b
100:
pop {r1-r8,lr} @ restaur registers bx lr @return
/************************************/ /* Strings case sensitive comparisons */ /************************************/ /* r0 et r1 contains the address of strings */ /* return 0 in r0 if equals */ /* return -1 if string r0 < string r1 */ /* return 1 if string r0 > string r1 */ comparStrings:
push {r1-r4} @ save des registres mov r2,#0 @ counter
1:
ldrb r3,[r0,r2] @ byte string 1 ldrb r4,[r1,r2] @ byte string 2 cmp r3,r4 movlt r0,#-1 @ small movgt r0,#1 @ greather bne 100f @ not equals cmp r3,#0 @ 0 end string moveq r0,#0 @ equal beq 100f @ end string add r2,r2,#1 @ else add 1 in counter b 1b @ and loop
100:
pop {r1-r4} bx lr
/***************************************************/ /* ROUTINES INCLUDE */ /***************************************************/ .include "../affichage.inc" </lang>
Enter command (or quit to stop) : riG RIGHT Enter command (or quit to stop) : rePEAT REPEAT Enter command (or quit to stop) : copies *error* Enter command (or quit to stop) : put PUT Enter command (or quit to stop) : mo MOVE Enter command (or quit to stop) : rest RESTORE Enter command (or quit to stop) : types *error* Enter command (or quit to stop) : fup. *error* Enter command (or quit to stop) : 6 *error* Enter command (or quit to stop) : poweRin POWERINPUT Enter command (or quit to stop) : quit QUIT
AutoHotkey
<lang AutoHotKey>; Setting up command table as one string str = (
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
) str := StrReplace(str,"`n")
- comTable turns the command table string into an array
- comTableCapsCount creates an array with the count of capital values for each word
comTable := StrSplit(RegExReplace(str, "\s+", " "), " ") comTableCapsCount := [] for cmds in comTable comTableCapsCount.push(StrLen(RegExReplace(comTable[cmds], "[a-z]")))
- Take and process user input into an array of abbreviations
InputBox, abbrev, Command, Type in your command(s).`n If you have several commands`, leave spaces between them. abbrev := Trim(abbrev) StringLower, lowerCaseAbbrev, abbrev abbrev := StrSplit(RegExReplace(abbrev, "\s+", " "), " ")
- Double loop compares abbreviations to commands in command table
Loop % abbrev.MaxIndex() { count := A_Index found := false for cmds in comTable { command := SubStr(comTable[cmds], 1, StrLen(abbrev[count])) StringLower, lowerCaseCommand, command if (lowerCaseCommand = abbrev[count]) and (StrLen(abbrev[count]) >= comTableCapsCount[cmds]) { StringUpper, foundCmd, % comTable[cmds] found := true } } if (found) result .= " " foundCmd else result .= " *error*" } MsgBox % Trim(result) </lang>
- Output:
input: riG rePEAT copies put mo rest types fup. 6 poweRin output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
AWK
<lang AWK>#!/usr/bin/awk -f BEGIN { FS=" "; split(" 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" \ , CMD);
for (k=1; k <= length(CMD); k++) { cmd[k] = CMD[k]; sub(/[a-z]*$/,"",cmd[k]); # print "0: ",CMD[k],"\t",cmd[k]; } }
function GET_ABBR(input) { for (k2=1; k2<=length(CMD); k2++) { if (index(toupper(CMD[k2]),input)==1) { if (index(input,toupper(cmd[k2]))==1) { return toupper(CMD[k2]); } } } return "*error*"; }
{ R=""; for (k1=1; k1 <= NF; k1++) { R=R" "GET_ABBR(toupper($k1)) } print R; }
</lang>
- Output:
echo 'riG rePEAT copies put mo rest types fup. 6 poweRin'|./abbreviations_easy.awk RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
C
<lang c>#include <ctype.h>
- include <stdbool.h>
- include <stdio.h>
- include <stdlib.h>
- include <string.h>
const char* command_table =
"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";
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;
}
size_t get_min_length(const char* str, size_t n) {
size_t len = 0; while (len < n && isupper((unsigned char)str[len])) ++len; return len;
}
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 = get_min_length(word, word_len); new_cmd->cmd = uppercase(word, word_len); 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;
}</lang>
- Output:
input: riG rePEAT copies put mo rest types fup. 6 poweRin output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
C++
<lang cpp>#include <algorithm>
- include <cctype>
- include <iostream>
- include <sstream>
- include <string>
- include <vector>
const char* command_table =
"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";
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;
}
// 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); });
}
size_t get_min_length(const std::string& str) {
size_t len = 0, n = str.length(); while (len < n && std::isupper(static_cast<unsigned char>(str[len]))) ++len; return len;
}
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::vector<command> commands; std::istringstream is(table); std::string word; while (is >> word) { // count leading uppercase characters size_t len = get_min_length(word); // then convert to uppercase uppercase(word); 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;
}</lang>
- Output:
input: riG rePEAT copies put mo rest types fup. 6 poweRin output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Delphi
<lang Delphi> program Abbreviations_Easy;
{$APPTYPE CONSOLE}
uses
System.SysUtils;
const
_TABLE_ = '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 ';
function validate(commands, words: TArray<string>; minLens: TArray<Integer>):
TArray<string>;
begin
SetLength(result, 0); if Length(words) = 0 then exit; 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 (minLens[i] = 0) or (wlen < minLens[i]) or (wlen > length(command)) then continue;
var c := command.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;
begin
var table := _TABLE_.Trim; var commands := table.Split([' '], TStringSplitOptions.ExcludeEmpty); var clen := Length(commands); var minLens: TArray<integer>; SetLength(minLens, clen); for var i := 0 to clen - 1 do begin var count := 0; for var c in commands[i] do begin if (c >= 'A') and (c <= 'Z') then inc(count); end; minLens[i] := count; end;
var sentence := 'riG rePEAT copies put mo rest types fup. 6 poweRin'; var words := sentence.Split([' '], TStringSplitOptions.ExcludeEmpty); var results := validate(commands, words, minLens); Write('user words: '); for var j := 0 to Length(words) - 1 do Write(words[j].PadRight(1 + length(results[j]))); Write(#10, 'full words: '); Writeln(string.Join(' ', results)); Readln;
end.</lang>
Euphoria
<lang Euphoria> include std/text.e -- for upper conversion include std/console.e -- for display include std/sequence.e
sequence ct = """ 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 """ ct = upper(split(join(split(ct,"\n")," ")," "))
object input = remove_all("\n",upper(remove_all("",split(gets(0))))) display(validate(input))
function validate(object words)
object results = repeat("*error*",length(words)) -- build an output list; integer x for i = 1 to length(words) do
words[i] = remove_all('\n',words[i]) -- final word in input line (may) have \n, get rid of it; for j = 1 to length(ct) do x = match(words[i],ct[j]) if x = 1 then results[i] = ct[j] -- replace this slot in the output list with the "found" word; exit -- and don't look further into the list; end if end for
end for return flatten(join(results," ")) -- convert sequence of strings into one string, words separated by a single space; end function </lang>
- Output:
riG rePEAT copies put mo rest types fup. 6 poweRin RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Factor
<lang factor>USING: arrays ascii assocs combinators.short-circuit io kernel literals math qw sequences sequences.extras splitting.extras ; IN: rosetta-code.abbreviations-easy
CONSTANT: commands qw{ 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 }
CONSTANT: user-input $[ "riG rePEAT copies put mo rest " "types fup. 6 poweRin" append ]
- starts-with? ( cand com -- ? ) [ >upper ] bi@ start 0 = ;
- capitals ( str -- n ) [ LETTER? ] count ;
- min-len? ( candidate command -- ? ) capitals swap length <= ;
- not-longer? ( candidate command -- ? ) [ length ] bi@ <= ;
- permitted? ( candidate command -- ? ) dup [ letter? ] count 0
> [ [ >upper ] bi@ = ] dip or ;
- valid-abbr? ( candidate command -- ? )
{ [ permitted? ] [ starts-with? ] [ min-len? ] [ not-longer? ] } 2&& ;
- find-command ( candidate -- command/f )
commands swap [ swap valid-abbr? ] curry find nip ;
- process-candidate ( candidate -- abbr/error )
find-command [ >upper ] [ "*error*" ] if* ;
- process-user-string ( str -- seq ) dup "" = [ drop "" ]
[ " " split-harvest [ process-candidate ] map ] if ;
- .abbr ( input -- )
[ " " split-harvest ] [ process-user-string ] bi zip [ first2 32 pad-longest 2array ] map [ keys ] [ values ] bi [ " " join ] bi@ [ "User words: " write print ] [ "Full words: " write print ] bi* ;
- main ( -- ) user-input "" [ .abbr ] bi@ ;
MAIN: main</lang>
- 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 User words: Full words:
Go
<lang go>package main
import (
"fmt" "strings"
)
var table =
"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 "
func validate(commands, words []string, minLens []int) []string {
results := make([]string, 0) if len(words) == 0 { return results } 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 main() {
table = strings.TrimSpace(table) commands := strings.Fields(table) clen := len(commands) minLens := make([]int, clen) for i := 0; i < clen; i++ { count := 0 for _, c := range commands[i] { if c >= 'A' && c <= 'Z' { count++ } } minLens[i] = count } sentence := "riG rePEAT copies put mo rest types fup. 6 poweRin" words := strings.Fields(sentence) results := validate(commands, words, minLens) fmt.Print("user words: ") for j := 0; j < len(words); j++ { fmt.Printf("%-*s ", len(results[j]), words[j]) } fmt.Print("\nfull words: ") fmt.Println(strings.Join(results, " "))
}</lang>
- 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
<lang haskell> import Data.Maybe (fromMaybe) import Data.List (find, isPrefixOf) import Data.Char (toUpper, isUpper)
isAbbreviationOf :: String -> String -> Bool isAbbreviationOf abbreviation command =
minimumPrefix `isPrefixOf` normalizedAbbreviation && normalizedAbbreviation `isPrefixOf` normalizedCommand where normalizedAbbreviation = map toUpper abbreviation normalizedCommand = map toUpper command minimumPrefix = takeWhile isUpper command
expandAbbreviation :: String -> String -> Maybe String
expandAbbreviation commandTable abbreviation = do
command <- find (isAbbreviationOf abbreviation) (words commandTable) return $ map toUpper command
commandTable = unwords [
"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"]
main :: IO ()
main = do
input <- getLine let abbreviations = words input let commands = map (fromMaybe "*error*" . expandAbbreviation commandTable) abbreviations putStrLn $ unwords results
</lang>
J
Using the expand definition as well as its dependencies from Abbreviations, simple#J we convert this command table into the form with the abbreviation length given as a number. <lang J>
COMMAND_TABLE=: noun define
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 ) 'CAPA CAPZ'=:a.i.'AZ' CT =: (, 3 ": [: +/ (CAPA&<: *. <:&CAPZ)@:(a.&i.))&.>&.:;: CRLF -.~ COMMAND_TABLE user_words =: 'riG rePEAT copies put mo rest types fup. 6 poweRin' CT expand user_words
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
</lang>
Java
<lang Java>import java.util.HashMap; import java.util.Map; import java.util.Scanner;
public class AbbreviationsEasy {
private static final Scanner input = new Scanner(System.in); private static final String COMMAND_TABLE = " Add ALTer BAckup Bottom CAppend Change SCHANGE CInsert CLAst COMPress COpy\n" + " COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find\n" + " NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput\n" + " Join SPlit SPLTJOIN LOAD Locate CLocate LOWercase UPPercase LPrefix MACRO\n" + " MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD Query QUIT\n" + " READ RECover REFRESH RENum REPeat Replace CReplace RESet RESTore RGTLEFT\n" + " RIght LEft SAVE SET SHift SI SORT SOS STAck STATus TOP TRAnsfer Type Up";
public static void main(String[] args) { String[] cmdTableArr = COMMAND_TABLE.split("\\s+"); Map<String, Integer> cmd_table = new HashMap<String, Integer>();
for (String word : cmdTableArr) { //Populate words and number of caps cmd_table.put(word, countCaps(word)); }
System.out.print("Please enter your command to verify: "); String userInput = input.nextLine(); String[] user_input = userInput.split("\\s+");
for (String s : user_input) { boolean match = false; //resets each outer loop for (String cmd : cmd_table.keySet()) { if (s.length() >= cmd_table.get(cmd) && s.length() <= cmd.length()) { String temp = cmd.toUpperCase(); if (temp.startsWith(s.toUpperCase())) { System.out.print(temp + " "); match = true; } } } if (!match) { //no match, print error msg System.out.print("*error* "); } } }
private static int countCaps(String word) { int numCaps = 0; for (int i = 0; i < word.length(); i++) { if (Character.isUpperCase(word.charAt(i))) { numCaps++; } } return numCaps; }
} </lang>
- Output:
Please enter your command to verify: riG rePEAT copies put mo rest types fup. 6 poweRin RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
JavaScript
Deno
Works in Browsers as well, uses ES6. Most of the hardwork was done by the RegEx engine. <lang javascript> var abr=`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` .split(/\W+/).map(_=>_.trim())
function escapeRegex(string) {
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
} var input = prompt(); console.log(input.length==0?null:input.trim().split(/\s+/)
.map( (s=>abr.filter( a=>(new RegExp('^'+escapeRegex(s),'i')) .test(a)&&s.length>=a.match(/^[A-Z]+/)[0].length
)[0]) )
.map(_=>typeof _=="undefined"?"*error*":_).join(' ')
)
</lang>
jq
<lang jq> def commands:
"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 ";
- produce a "dictionary" in the form of an array of {prefix, word} objects
def dictionary:
reduce (splits(" +") | select(length>0)) as $w ([]; . + [$w | {prefix: sub("[a-z]+";""), word: ascii_upcase} ]);
def translate($dict):
# input: a string; $command: a {prefix, word} object def match($command): . as $uc | startswith($command.prefix) and ($command.word | startswith($uc));
if length==0 then "" else ascii_upcase | first($dict[] as $command | select( match($command) ) | $command | .word) // "*error*" end;
- Emit the translation of an entire "sentence"
def translation:
(commands|dictionary) as $dict | reduce splits(" +") as $w (""; . + ($w|translate($dict)) + " ") | sub(" $";"");
- Example:
"riG rePEAT copies put mo rest types fup. 6 poweRin" | translation </lang>
Invocation: jq -n -f abbreviations.jq
- Output:
"RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT"
Julia
<lang julia>const table =
"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 "
function validate(commands::AbstractVector{<:AbstractString},
minlens::AbstractVector{<:Integer}, words::AbstractVector{<:AbstractString}) r = String[] for word in words matchfound = false for (i, command) in enumerate(commands) if iszero(minlens[i]) || length(word) ∉ minlens[i]:length(command) continue end if startswith(lowercase(command), lowercase(word)) push!(r, uppercase(command)) matchfound = true break end end !matchfound && push!(r, "*error*") end return r
end
commands = split(strip(table)) minlens = count.(isupper, commands) sentence = "riG rePEAT copies put mo rest types fup. 6 poweRin" words = split(sentence) result = validate(commands, minlens, words) println("User words: ", join(lpad.(words, 11))) println("Full words: ", join(lpad.(result, 11)))</lang>
- 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
Kotlin
<lang scala>// version 1.1.4-3
val r = Regex("[ ]+")
val table =
"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 "
fun validate(commands: List<String>, minLens: List<Int>, words: List<String>): List<String> {
if (words.isEmpty()) return emptyList<String>() val results = mutableListOf<String>() for (word in words) { var matchFound = false for ((i, command) in commands.withIndex()) { if (minLens[i] == 0 || word.length !in minLens[i] .. command.length) continue if (command.startsWith(word, true)) { results.add(command.toUpperCase()) matchFound = true break } } if (!matchFound) results.add("*error*") } return results
}
fun main(args: Array<String>) {
val commands = table.trimEnd().split(r) val minLens = MutableList(commands.size) { commands[it].count { c -> c.isUpperCase() } } val sentence = "riG rePEAT copies put mo rest types fup. 6 poweRin" val words = sentence.trim().split(r) val results = validate(commands, minLens, words) print("user words: ") for (j in 0 until words.size) print("${words[j].padEnd(results[j].length)} ") print("\nfull words: ") for (j in 0 until results.size) print("${results[j]} ") println()
}</lang>
- 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
<lang Lua>#!/usr/bin/lua
local list1 = [[
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 ]]
local indata1 = [[riG rePEAT copies put mo rest types
fup. 6 poweRin]]
local indata2 = ALT aLt ALTE ALTER AL ALF ALTERS TER A local indata3 = o ov oVe over overL overla
local function split(text)
local result = {} for w in string.gmatch(text, "%g+") do result[#result+1]=w -- print(#result,w,#w) end return result
end
local function print_line( t )
for i = 1,#t do io.write( string.format("%s ", t[i] ) ) end print()
end
local function is_valid(cmd,abbrev)
--print(abbrev,cmd,"##") local sm = string.match( cmd:lower(), abbrev:lower() ) if sm == nil then return -1 end
-- test if any lowercase in "cmd" if false then do -- NOTE!: requirement spec error .. put not equal PUT
local lowcase = string.match(cmd,"%l+") if lowcase == nil then return -2 end if #lowcase < 1 then return -3 end end
end -- test if abbrev is too long if #abbrev > #cmd then return -4 end
--- num caps in "cmd" is minimum length of abbrev local caps = string.match(cmd,"%u+") if #abbrev < #caps then return -5 end
local s1 = abbrev:sub(1,#caps) local s2 = cmd:sub(1,#caps) if s1:lower() ~= s2:lower() then return -6 end
return 1
end
local function start()
local t1 = {} local t2 = {} local result = {} t1 = split(list1) t2 = split(indata1) print_line(t2);
for i = 1,#t2 do good = 0 for j = 1,#t1 do
local abbrev = t2[i] local cmd = t1[j] good = is_valid(cmd,abbrev) if good==1 then do result[#result+1] = t1[j]:upper() break end end --if
end --for j if good < 1 then result[#result+1] = "*error*" end end --for i print_line(result)
end
start() -- run the program </lang>
- Output:
Please enter your command to verify: riG rePEAT copies put mo rest types fup. 6 poweRin RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Mathematica/Wolfram Language
<lang Mathematica>ClearAll[ct, FunctionMatchQ, ValidFunctionQ, ProcessString] ct = "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";
ct = FixedPoint[StringReplace[{"\n" -> "", Longest[" " ..] -> " "}], ct]; ct = StringSplit[ct, " "]; FunctionMatchQ[func_String, test_String] := Module[{min, max, l},
min = StringCount[func, Alternatives @@ CharacterRange["A", "Z"]]; 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[val]] ]
ProcessString[test_String] := Module[{parts},
parts = StringSplit[test]; StringRiffle[ValidFunctionQ /@ parts, " "] ]
ProcessString["riG rePEAT copies put mo rest types fup. 6 poweRin"]</lang>
- Output:
"RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT"
MATLAB / Octave
<lang Matlab> function R = abbreviations_easy(input)
CMD=strsplit(['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' ],' ');
for k=1:length(CMD) cmd{k} = CMD{k}(CMD{k}<'a'); CMD{k} = upper(CMD{k}); end
ilist = strsplit(input,' '); R = ; for k=1:length(ilist) input = upper(ilist{k});
ix = find(strncmp(CMD, input, length(input))); result= '*error*'; for k = ix(:)', if strncmp(input, cmd{k}, length(cmd{k})); result = CMD{k}; end end R = [R,' ',result]; end </lang>
- Output:
abbreviations_easy('riG rePEAT copies put mo rest types fup. 6 poweRin') ans = RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Nanoquery
<lang nanoquery>import map
COMMAND_TABLE = " Add ALTer BAckup Bottom CAppend Change SCHANGE CInsert CLAst COMPress COpy\n" +\
" COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find\n" +\ " NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput\n" +\ " Join SPlit SPLTJOIN LOAD Locate CLocate LOWercase UPPercase LPrefix MACRO\n" +\ " MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD Query QUIT\n" +\ " READ RECover REFRESH RENum REPeat Replace CReplace RESet RESTore RGTLEFT\n" +\ " RIght LEft SAVE SET SHift SI SORT SOS STAck STATus TOP TRAnsfer Type Up"
def countCaps(word)
if len(word) < 1 return 0 end
numCaps = 0 for i in range(0, len(word) - 1) if word[i] = upper(word[i]) numCaps += 1 end end return numCaps
end
cmdTableArr = COMMAND_TABLE.split("\\s+") cmd_table = new(map)
for word in cmdTableArr
cmd_table.put(word, countCaps(word))
end
print "Please enter your command to verify: " user_input = input().split("\\s+")
for s in user_input
match = false for i in range(0, len(cmd_table.keys) - 1) if (len(s) >= cmd_table.get(cmd_table.keys[i])) and (len(s) <= len(cmd_table.keys[i])) temp = upper(cmd_table.keys[i]) if temp .startswith. upper(s) print temp + " " match = true end end end
if !match print "*error* " end
end</lang>
- Output:
Please enter your command to verify: riG rePEAT copies put mo rest types fup. 6 poweRin RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Nim
This is a translation of Kotlin solution with some modifications. <lang Nim> import sequtils import strutils
const Commands = "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"
- ---------------------------------------------------------------------------------------------------
proc validate(words, commands: seq[string]; minLens: seq[int]): seq[string] =
if words.len == 0: return
for word in words: var matchFound = false for i, command in commands: if word.len notin minLens[i]..command.len: continue if command.toUpper.startsWith(word.toUpper): result.add(command.toUpper) matchFound = true break if not matchFound: result.add("*error*")
- ---------------------------------------------------------------------------------------------------
var commands = Commands.splitWhitespace() var minLens = newSeq[int](commands.len) # Count of uppercase characters. for idx, command in commands:
minLens[idx] = command.countIt(it.isUpperAscii)
while true:
try: stdout.write "Input? " let words = stdin.readline().strip().splitWhitespace() let results = words.validate(commands, minLens) stdout.write("\nUser words: ") for i, word in words: stdout.write(word.alignLeft(results[i].len) & ' ') stdout.write("\nFull words: ") for result in results: stdout.write(result & ' ') stdout.write("\n\n")
except EOFError: echo "" break
</lang>
- Output:
Input? riG rePEAT copies put mo rest types fup. 6 poweRin 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? User words: Full words: Input?
OCaml
<lang ocaml>let 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"
let user =
"riG rePEAT copies put mo rest types fup. 6 poweRin"
let char_is_uppercase c =
match c with | 'A'..'Z' -> true | _ -> false
let get_abbr s =
let seq = String.to_seq s in let seq = Seq.filter char_is_uppercase seq in (String.of_seq seq)
let () =
let cmds = Str.split (Str.regexp "[ \r\n]+") cmds in let cmds = List.map (fun s -> get_abbr s, String.uppercase_ascii s ) cmds in let user = Str.split (Str.regexp "[ \r\n]+") user in let r = List.map (fun ucmd -> let n = String.length ucmd in let find_abbr (abbr, cmd) = let na = String.length abbr in let nc = String.length cmd in if n < na || nc < n then false else let sub = String.sub cmd 0 n in (sub = String.uppercase_ascii ucmd) in match List.find_opt find_abbr cmds with | Some (_, found) -> found | None -> "*error*" ) user in print_endline (String.concat " " r)</lang>
- Output:
$ ocaml str.cma abbr.ml RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Pascal
Free Pascal
only modified to get the implicit declared variables and types.
<lang pascal> program Abbreviations_Easy; {$IFDEF WINDOWS}
{$APPTYPE CONSOLE}
{$ENDIF} {$IFDEF FPC}
{$MODE DELPHI} uses SysUtils;
{$ELSE}
uses System.SysUtils;
{$ENDIF}
const
_TABLE_ = '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 ';
function validate(commands, words: TArray<string>; minLens: TArray<Integer>):
TArray<string>;
var
wd,c,command,w : String; wdIdx,wlen,i : integer; matchFound : boolean;
begin
SetLength(result, 0); if Length(words) = 0 then exit; for wdIdx := Low(words) to High(words) do begin wd := words[wdIdx]; matchFound := false; wlen := wd.Length; for i := 0 to High(commands) do begin command := commands[i]; if (minLens[i] = 0) or (wlen < minLens[i]) or (wlen > length(command)) then continue;
c := command.ToUpper; 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; var
results,commands,words :TArray<string>; table,sentence :String; minLens: TArray<integer>; cLen,i,j,count : integer; c:char;
begin
table := _TABLE_.Trim; commands := table.Split([' '], TStringSplitOptions.ExcludeEmpty); clen := Length(commands); SetLength(minLens, clen); for i := 0 to clen - 1 do begin count := 0; For j := length(commands[i]) downto 1 do begin c := commands[i][j]; if (c >= 'A') and (c <= 'Z') then inc(count); end; minLens[i] := count; end;
sentence := 'riG rePEAT copies put mo rest types fup. 6 poweRin'; words := sentence.Split([' '], TStringSplitOptions.ExcludeEmpty); results := validate(commands, words, minLens); Write('user words: '); for j := 0 to Length(words) - 1 do Write(words[j].PadRight(1 + length(results[j]))); Write(#10, 'full words: ');
// FOr fpc 3.0.4 on TIO.RUN
for j := 0 to Length(words) - 1 do Write(results[j],' ');
// fpc 3.2.2 will do // Writeln(string.Join(' ', results));
{$IFDEF WINDOWS} Readln; {$ENDIF}
end.</lang>
- @TIO.RUN fpc 3.0.4:
user words: riG rePEAT copies put mo rest types fup. 6 poweRin full words: RIGHT REPEAT error* PUT MOVE RESTORE error* error* error* POWERINPUT
Perl
<lang perl>@c = (join ' ', qw< 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 Replace REPeat CReplace RESet RESTore RGTLEFT RIght LEft SAVE SET SHift SI SORT SOS STAck STATus TOP TRAnsfer Type Up >) =~ /([A-Z]+)([a-z]*)(?:\s+|$)/g;
my %abr = ( => , ' ' => ); for ($i = 0; $i < @c; $i += 2) {
$sl = length($s = $c[$i] ); $ll = length($l = uc $c[$i+1]); $abr{$s} = $w = $s.$l; map { $abr{substr($w, 0, $_)} = $w } $sl .. $ll; $abr{$w} = $w; # full command should always work
}
$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"</lang>
- Output:
Input: riG rePEAT copies put mo rest types fup. 6 poweRin Output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Phix
constant abbrtxt = """ 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 """, input = "riG rePEAT copies put mo rest types fup. 6 poweRin" function set_min_lengths(sequence a) sequence res = {} for i=1 to length(a) do string ai = a[i], uai = upper(ai) for j=-length(ai) to 0 do if j=0 or ai[j]!=uai[j] then res = append(res,{ai,length(ai)+j}) exit end if end for 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
PHP
<lang php> // note this is php 7.x $commands = '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';
$input = 'riG rePEAT copies put mo rest types fup. 6 poweRin'; $expect = 'RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT'; $table = makeCommandTable($commands); $table_keys = array_keys($table);
$inputTable = processInput($input);
foreach ($inputTable as $word) {
$rs = searchCommandTable($word, $table); if ($rs) { $output[] = $rs; } else { $output[] = '*error*'; }
} echo 'Input: '. $input. PHP_EOL; echo 'Output: '. implode(' ', $output). PHP_EOL;
function searchCommandTable($search, $table) {
foreach ($table as $key => $value) { if ((strtoupper(substr($value['word'], 0, strlen($search))) === strtoupper($search)) && (strlen($search) >= $value['min_length'])) { return $key; } } return false;
}
function processInput($input) {
$input = preg_replace('!\s+!', ' ', $input); $pieces = explode(' ', trim($input)); return $pieces;
}
function makeCommandTable($commands) {
$commands = preg_replace('!\s+!', ' ', $commands); $pieces = explode(' ', trim($commands)); foreach ($pieces as $word) { $rs[strtoupper($word)] = ['word'=>$word, 'min_length' => preg_match_all("/[A-Z]/", $word)]; } return $rs;
}</lang>
- 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
PowerShell
<lang powershell><# Start with a string of the commands #> $cmdTableStr = "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"
<# String of inputs #> $userWordStr = "riG rePEAT copies put mo rest types fup. 6 poweRin"
$outputStr = $null # Set this string to null only so all variables are intialized
$cmdTabArray = @() # Arrays for the commands and the inputs $userWordArray = @()
<# Split the strings into arrays using a space as the delimiter.
This also removes "blank" entries, which fits the requirement "A blank input (or a null input) should return a null string." #>
$cmdTabArray = $cmdTableStr.Split(" ", [System.StringSplitOptions]::RemoveEmptyEntries) $userWordArray = $userWordStr.Split(" ", [System.StringSplitOptions]::RemoveEmptyEntries)
<# Begins a loop to iterate through the inputs #> foreach($word in $userWordArray) {
$match = $false # Variable set to false so that if a match is never found, the "*error*" string can be appended foreach($cmd in $cmdTabArray) { <# This test: 1) ensures inputs match the leading characters of the command 2) are abbreviations of the command 3) the abbreviations is at least the number of capital characters in the command #> if($cmd -like "$word*" -and ($word.Length -ge ($cmd -creplace '[a-z]').Length)) { $outputStr += $cmd.ToUpper() + " " # Adds the command in all caps to the output string $match = $true # Sets the variable so that "*error*" is not appended break # Break keep the loop from continuing and wasting time once a match was found } } if($match -eq $false){ $outputStr += "*error* " } # Appends error if no match was found
}
- Below lines display the input and output
"User text: " + $userWordStr "Full text: " + $outputStr</lang>
- Output:
User text: riG rePEAT copies put mo rest types fup. 6 poweRin Full text: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Python
<lang python>command_table_text = \ """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"""
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 by counting capital letters. a word that does not have capital letters gets it's full length as the minimum. """ command_table = dict() for word in command_table_text.split(): abbr_len = sum(1 for c in word if c.isupper()) if abbr_len == 0: abbr_len = len(word) command_table[word] = abbr_len 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)</lang>
- 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
Racket
<lang racket>#lang racket
(define command-string
"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")
(define input-string
"riG rePEAT copies put mo rest types fup. 6 poweRin")
(define (make-command command)
(cons (string-upcase command) (list->string (takef (string->list command) char-upper-case?))))
(define commands (map make-command (string-split command-string)))
(string-join
(for/list ([s (in-list (string-split input-string))]) (define up (string-upcase s)) (or (for/or ([command (in-list commands)]) (match-define (cons full-command abbrev) command) (and (string-prefix? up abbrev) (string-prefix? full-command up) full-command)) "*error*")) " ")</lang>
- Output:
"RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT"
Raku
(formerly Perl 6)
Demonstrate that inputting an empty string returns an empty string in addition to the required test input.
<lang perl6>< 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 > ~~ m:g/ ((<.:Lu>+) <.:Ll>*) /;
my %abr = => , |$/.map: {
my $abbrv = .[0].Str.fc; |map { $abbrv.substr( 0, $_ ) => $abbrv.uc }, .[0][0].Str.chars .. $abbrv.chars
};
sub abbr-easy ( $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-easy;
}</lang>
- 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
<lang REXX>/*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 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 MOve MODify 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'
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 legitimate command name from @.*/ L=verify(_, 'abcdefghijklmnopqrstuvwxyz', "M") /*maybe get abbrev's len.*/ if L==0 then L=length(_) /*0? Command name 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. */</lang>
- 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
<lang ruby>#!/usr/bin/env ruby
cmd_table = File.read(ARGV[0]).split user_str = File.read(ARGV[1]).split
user_str.each do |abbr|
candidate = cmd_table.find do |cmd| cmd.count('A-Z') <= abbr.length && abbr.casecmp(cmd[0...abbr.length]).zero? end
print candidate.nil? ? '*error*' : candidate.upcase
print ' '
end
puts </lang>
- Output:
$ ./abbreviations_easy.rb cmd_table user_str RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Rust
<lang rust>use std::collections::HashMap;
fn main() {
let commands = " 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 \ "; let split = commands.split_ascii_whitespace(); let count_hashtable: HashMap<&str, usize> = split.map(|word| { (word, word.chars().take_while(|c| c.is_ascii_uppercase()).count()) }).collect();
let line = "riG rePEAT copies put mo rest types fup. 6 poweRin"; let mut words_vec: Vec<String> = vec![]; for word in line.split_ascii_whitespace() { let split = commands.split_ascii_whitespace(); let abbr = split.filter(|x| { x.to_ascii_lowercase().starts_with(&word.to_ascii_lowercase()) && word.len() >= *count_hashtable.get(x).unwrap() }).next(); words_vec.push(match abbr { Some(word) => word.to_ascii_uppercase(), None => String::from("*error*"), }); } let corrected_line = words_vec.join(" "); println!("{}", corrected_line);
} </lang>
- Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Scala
<lang Scala> object Main extends App {
implicit class StrOps(i: String) { def isAbbreviationOf(target: String): 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 >= target.count(_.isUpper) && checkPAsPrefixOfM(i.toList, target.toList) } }
val commands = """ |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 """.stripMargin.replace("\n", " ").trim.split(" ")
val input = "riG rePEAT copies put mo rest types fup. 6 poweRin".split(" ").filter(!_.isEmpty)
val resultLine = input.map{ i => commands.find(c => i.isAbbreviationOf(c)).map(_.toUpperCase).getOrElse("*error*") }.mkString(" ")
println(resultLine)
} </lang>
- Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Tcl
<lang tcl> 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 $result </lang>
- Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
VBA
<lang vb>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 ALTer BAckup Bottom CAppend Change SCHANGE CInsert CLAst COMPress COpy " s = s & "COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find " s = s & "NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput " s = s & "Join SPlit SPLTJOIN LOAD Locate CLocate LOWercase UPPercase LPrefix MACRO " s = s & "MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD Query QUIT " s = s & "READ RECover REFRESH RENum REPeat Replace CReplace RESet RESTore RGTLEFT " s = s & "RIght LEft SAVE SET SHift SI SORT SOS STAck STATus TOP TRAnsfer Type Up " commandtable = Split(s, " ") Dim i As Integer For Each word In commandtable If Len(word) > 0 Then i = 1 Do While Mid(word, i, 1) >= "A" And Mid(word, i, 1) <= "Z" i = i + 1 Loop command_table.Add Key:=word, Item:=i - 1 End If Next word 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</lang>
- 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
Vedit macro language
<lang vedit>// Command table: Buf_Switch(#10=Buf_Free) Ins_Text("
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
")
// Example input: Buf_Switch(#11=Buf_Free) Ins_Text("riG rePEAT copies put mo rest types fup. 6 poweRin ") BOF
// Main program
- 20 = Reg_Free() // Text register for the word to be converted
Repeat(ALL) {
Buf_Switch(#11) // Buffer for example input Search("|!|X", ERRBREAK) // Find next non-space character #30 = Cur_Pos // #30 = begin of a word Search("|X", NOERR+NORESTORE) // Find whitespace (end of the word) Reg_Copy_Block(#20, #30, Cur_Pos) // Get the word to text register #20 Call("acronym_to_word") // Convert acronym to full word Reg_Type(#20) // Display the full word Type_Char(' ') // Display a space character
} Buf_Switch(#10) Buf_Quit(OK) // Clean-up Buf_Switch(#11) Buf_Quit(OK) Reg_Empty(#20) Return
// Convert an acronym to full word in uppercase // Input: @(#20) = the acronym // Return: @(#20) = the full word //
- acronym_to_word:
if (Reg_Size(#20) == 0) { // If zero length input,
return // return zero length string
} Buf_Switch(#10) // Switch to command table BOF While (!At_EOF) {
if (Search("|S|@(#20)", NOERR)) { // Find (the first part of) the word
Char // Skip the separator #31 = Cur_Pos // #31 = Begin of the acronym Char(Reg_Size(#20)) // Check if the acronym is log enough if (Cur_Char < 'A' || Cur_Char > 'Z') { // Not a capital letter, verified Search("|X") // Find the end of the word Reg_Copy_Block(#20, #31, Cur_Pos) // Get the word into text register #20 Buf_Switch(Buf_Free) // Convert to upper case using tmp buffer Reg_Ins(#20) Case_Upper_Block(0, Cur_Pos) Reg_Copy_Block(#20, 0, Cur_Pos) Buf_Quit(OK) break // Word found, exit loop }
} else { // Not found
Reg_Set(#20, "*error*") break
}
} Return</lang>
- Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
Wren
<lang ecmascript>import "/fmt" for Fmt import "/str" for Str
var table =
"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"
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 commands = table.split(" ") // get rid of empty entries for (i in commands.count-1..0) if (commands[i] == "") commands.removeAt(i) var clen = commands.count var minLens = [0] * clen for (i in 0...clen) {
var count = 0 for (c in commands[i].codePoints) { if (c >= 65 && c <= 90) count = count + 1 // A to Z } minLens[i] = count
} 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(" "))</lang>
- 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
<lang Yabasic>data "Add ALTer BAckup Bottom CAppend Change SCHANGE CInsert CLAst COMPress COpy" data "COUnt COVerlay CURsor DELete CDelete Down DUPlicate Xedit EXPand EXTract Find" data "NFind NFINDUp NFUp CFind FINdup FUp FOrward GET Help HEXType Input POWerinput" data "Join SPlit SPLTJOIN LOAD Locate CLocate LOWercase UPPercase LPrefix MACRO" data "MErge MODify MOve MSG Next Overlay PARSE PREServe PURge PUT PUTD Query QUIT" data "READ RECover REFRESH RENum REPeat Replace CReplace RESet RESTore RGTLEFT" data "RIght LEft SAVE SET SHift SI SORT SOS STAck STATus TOP TRAnsfer Type Up" data ""
dim abrev$(1)
do
read a$ if a$ = "" break s$ = s$ + " " + a$
loop
size = token(s$, abrev$())
do
input "Input abbreviation: " a$ l1 = len(a$) if l1 = 0 break test = false for i = 1 to size l2 = uppers(abrev$(i)) if lower$(left$(abrev$(i), l1)) = lower$(left$(a$, l1)) and l1 >= l2 then print upper$(abrev$(i)) test = true end if next if not test print "*error*"
loop
sub uppers(s$)
local l, i, c$, n l = len(s$) for i = 1 to l c$ = mid$(s$, i, 1) if c$ >= "A" and c$ <= "Z" n = n + 1 next return n
end sub </lang>
zkl
Rather more brute force than I'd like but hashing the command table is just too much code. And the table is so small... <lang zkl>commands:=Data(0,String, // "Add\0ALTer\0..."
- <<<
"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 "
.split());
- <<<
testText:=" riG rePEAT copies put mo rest types " "fup. 6 poweRin";
testText.split().apply('wrap(word){
sz,w := word.len(),word + "*"; foreach c in (commands){ // rather inelegant but gotta ignore case // check for length requirement and, if there, verify if(c.matches(w) and sz>=(c-"abcdefghijklmnopqrstuvwxyz").len())
return(c.toUpper());
} "*error*"
.concat(" ").println();</lang>
- Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
- Programming Tasks
- Solutions by Programming Task
- 11l
- AArch64 Assembly
- Ada
- ALGOL 68
- ARM Assembly
- ARM Assembly examples needing attention
- Examples needing attention
- AutoHotkey
- AWK
- C
- C++
- Delphi
- System.SysUtils
- Euphoria
- Factor
- Go
- Haskell
- J
- Java
- JavaScript
- Jq
- Julia
- Kotlin
- Lua
- Mathematica
- Wolfram Language
- MATLAB
- Octave
- Nanoquery
- Nim
- OCaml
- Pascal
- Free Pascal
- Perl
- Phix
- PHP
- PowerShell
- Python
- Racket
- Raku
- REXX
- Ruby
- Rust
- Scala
- Tcl
- VBA
- Vedit macro language
- Wren
- Wren-fmt
- Wren-str
- Yabasic
- Zkl