Abbreviations, simple

From Rosetta Code
Abbreviations, simple is a draft programming task. It is not yet considered ready to be promoted as a complete task, for reasons that should be found in its talk page.

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


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

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


Notes concerning the above   command table:

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


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


An example test case to be used for this task

For a user string of:

 riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin

the computer program should return the string:

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


Related tasks



Forth[edit]

Works with any ANS Forth

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

include FMS-SI.f
include FMS-SILib.f
 
${ add 1 alter 3 backup 2 bottom 1 Cappend 2 change 1 Schange Cinsert 2 Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3 delete 3 Cdelete 2 down 1 duplicate
3 xEdit 1 expand 3 extract 3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
forward 2 get help 1 hexType 4 input 1 powerInput 3 join 1 split 2 spltJOIN load
locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2 macro merge 2 modify 3 move 2
msg next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit read recover 3
refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
2 save set shift 2 si sort sos stack 3 status 4 top transfer 3 type 1 up 1 }
value list ' upper: list map:
 
: compare' { adr len $obj -- f }
len $obj size: > if false exit then
adr len $obj @: drop len compare 0= ;
 
: <= ( n1 n2 = f) 1+ swap > ;
 
: abbrev 0 0 { adr len obj1 obj2 -- }
list uneach:
list each: drop to obj1
begin
list each:
while
to obj2
obj2 @: >integer
if \ word followed by a number
len <= if adr len obj1 compare'
if obj1 p: exit then
then list each: if to obj1 else ." *error* " exit then
else \ word not followed by a number
adr len obj1 @: compare 0=
if obj1 p: exit then
obj2 to obj1
then
repeat ;
 
${ riG rePEAT copies put mo rest types fup. 6 poweRin }
value input-list ' upper: input-list map:
 
: valid-input ( adr len -- f)
over + swap do i [email protected] isalpha 0= if ." *error* " unloop false exit then loop true ;
 
: run
begin
input-list each:
while
dup @: valid-input
if @: abbrev space else drop then
repeat ;
 
 
run RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT ok
 
 

Kotlin[edit]

// version 1.1.4-3
 
val r = Regex("[ ]+")
 
val table =
"add 1 alter 3 backup 2 bottom 1 Cappend 2 change 1 Schange Cinsert 2 Clast 3 " +
"compress 4 copy 2 count 3 Coverlay 3 cursor 3 delete 3 Cdelete 2 down 1 duplicate " +
"3 xEdit 1 expand 3 extract 3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 " +
"forward 2 get help 1 hexType 4 input 1 powerInput 3 join 1 split 2 spltJOIN load " +
"locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2 macro merge 2 modify 3 move 2 " +
"msg next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit read recover 3 " +
"refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left " +
"2 save set shift 2 si sort sos stack 3 status 4 top transfer 3 type 1 up 1 "
 
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 splits = table.trimEnd().split(r)
val commands = mutableListOf<String>()
val minLens = mutableListOf<Int>()
var i = 0
while (true) {
commands.add(splits[i])
val len = splits[i].length
if (i == splits.size - 1) {
minLens.add(len)
break
}
val num = splits[++i].toIntOrNull()
if (num != null) {
minLens.add(minOf(num, len))
if (++i == splits.size) break
}
else minLens.add(len)
}
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()
}
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 

Perl 6[edit]

Works with: Rakudo version 2017.08

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

<
add 1 alter 3 backup 2 bottom 1 Cappend 2 change 1 Schange Cinsert 2 Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3 delete 3 Cdelete 2 down 1 duplicate
3 xEdit 1 expand 3 extract 3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
forward 2 get help 1 hexType 4 input 1 powerInput 3 join 1 split 2 spltJOIN load
locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2 macro merge 2 modify 3 move 2
msg next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit read recover 3
refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
2 save set shift 2 si sort sos stack 3 status 4 top transfer 3 type 1 up 1
> ~~ m:g/ (<.alpha>+) \s* (\d*) /;
 
my %abr = '' => '', |$/.map: {
my $abbrv = $_[0].Str.fc;
|map { $abbrv.substr( 0, $_ ) => $abbrv.uc },
+($_[1].Str || $_[0].Str.chars) .. $_[0].Str.chars;
};
 
sub abbr-simple ( $str ) { %abr{$str.fc} // '*error*' }
 
# Testing
for 'riG rePEAT copies put mo rest types fup. 6 poweRin', '' -> $str {
put ' Input: ', $str;
put 'Output: ', join ' ', $str.words.map: *.&abbr-simple;
}
Output:
 Input: riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
Output: RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT
 Input: 
Output: 

REXX[edit]

/*REXX program validates a user  "word"  against a  "command table"  with abbreviations.*/
parse arg uw /*obtain optional arguments from the CL*/
if uw='' then uw= 'riG rePEAT copies put mo rest types fup. 6 poweRin'
say 'user words: ' uw
 
@= 'add 1 alter 3 backup 2 bottom 1 Cappend 2 change 1 Schange Cinsert 2 Clast 3',
'compress 4 copy 2 count 3 Coverlay 3 cursor 3 delete 3 Cdelete 2 down 1 duplicate',
'3 xEdit 1 expand 3 extract 3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2',
'forward 2 get help 1 hexType 4 input 1 powerInput 3 join 1 split 2 spltJOIN load',
'locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2 macro merge 2 modify 3 move 2',
'msg next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit read recover 3',
'refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left',
'2 save set shift 2 si sort sos stack 3 status 4 top transfer 3 type 1 up 1'
 
say 'full words: ' validate(uw) /*display the result(s) to the terminal*/
exit /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
validate: procedure expose @; arg x; upper @ /*ARG capitalizes all the X words. */
$= /*initialize the return string to null.*/
do j=1 to words(x); _=word(x, j) /*obtain a word from the X list. */
do k=1 to words(@); a=word(@, k) /*get a legitmate command name from @.*/
L=word(@, k+1) /*··· and maybe get it's abbrev length.*/
if datatype(L, 'W') then k=k + 1 /*yuppers, it's an abbrev length.*/
else L=length(a) /*nope, it can't be abbreviated.*/
if abbrev(a, _, L) then do; $=$ a; iterate j; end /*is valid abbrev?*/
end /*k*/
$=$ '*error*' /*processed the whole list, not valid. */
end /*j*/
return strip($) /*elide the superfluous leading blank. */
output   when using the default input:
user words:  riG   rePEAT copies  put mo   rest    types   fup.    6       poweRin
full words:  RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT

zkl[edit]

commands:=Data(0,String,	// "add\01\0alter\0..."
#<<<
"add 1 alter 3 backup 2 bottom 1 Cappend 2 change 1 Schange Cinsert 2 Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3 delete 3 Cdelete 2 down 1 duplicate
3 xEdit 1 expand 3 extract 3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2
forward 2 get help 1 hexType 4 input 1 powerInput 3 join 1 split 2 spltJOIN load
locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2 macro merge 2 modify 3 move 2
msg next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit read recover 3
refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left
2 save set shift 2 si sort sos stack 3 status 4 top transfer 3 type 1 up 1"
.toUpper().split());
#<<<
 
var szs=Dictionary(); // [<index>:<length> ...]
n:=0; while(n<commands.len()){
cmd,nc := commands.readString(n), n + cmd.len() + 1;
len:=commands.readString(nc);
if(len.matches("[0-9]*")){ szs[n]=len.toInt(); n=nc+len.len()+1 }
else { szs[n]=cmd.len(); n=nc; }
}
 
testText:="riG rePEAT copies put mo rest types "
" fup. 6 poweRin";
 
testText.split().apply('wrap(w){
w=w.toUpper(); n:=0;
while(True){ // check for length requirement and, if there, verify
n=commands.find(w,n);
if(Void==n) return("*error*"); // end of loop if no match
c:=commands.readString(n);
if(w.len()>=szs.find(n,99999)) return(c);
n+=c.len();
}
}).concat(" ").println();
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT