Abbreviations, simple: Difference between revisions
(→{{header|Python}}: flagged as have no output as per the task's requirement.) |
|||
Line 358: | Line 358: | ||
=={{header|Python}}== |
=={{header|Python}}== |
||
{{output?}} |
|||
{{works with|Python|3.6}} |
{{works with|Python|3.6}} |
||
<lang python> |
<lang python> |
Revision as of 03:08, 11 August 2018
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
Works with any ANS Forth
Needs the FMS-SI (single inheritance) library code located here: http://soton.mpeforth.com/flag/fms/index.html <lang forth>include FMS-SI.f include FMS-SILib.f
${ add 1 alter 3 backup 2 bottom 1 Cappend 2 change 1 Schange Cinsert 2 Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3 delete 3 Cdelete 2 down 1 duplicate 3 xEdit 1 expand 3 extract 3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 forward 2 get help 1 hexType 4 input 1 powerInput 3 join 1 split 2 spltJOIN load locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2 macro merge 2 modify 3 move 2 msg next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit read recover 3 refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left 2 save set shift 2 si sort sos stack 3 status 4 top transfer 3 type 1 up 1 } value list ' upper: list map:
- compare' { adr len $obj -- f }
len $obj size: > if false exit then adr len $obj @: drop len compare 0= ;
- <= ( n1 n2 = f) 1+ swap > ;
- abbrev 0 0 { adr len obj1 obj2 -- }
list uneach: list each: drop to obj1 begin list each: while to obj2 obj2 @: >integer if \ word followed by a number len <= if adr len obj1 compare' if obj1 p: exit then then list each: if to obj1 else ." *error* " exit then else \ word not followed by a number adr len obj1 @: compare 0= if obj1 p: exit then obj2 to obj1 then repeat ;
${ riG rePEAT copies put mo rest types fup. 6 poweRin }
value input-list ' upper: input-list map:
- valid-input ( adr len -- f)
over + swap do i c@ isalpha 0= if ." *error* " unloop false exit then loop true ;
- run
begin input-list each: while dup @: valid-input if @: abbrev space else drop then repeat ;
run RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT ok
</lang>
Go
<lang go>package main
import(
"fmt" "strconv" "strings"
)
var table =
"add 1 alter 3 backup 2 bottom 1 Cappend 2 change 1 Schange Cinsert 2 Clast 3 " + "compress 4 copy 2 count 3 Coverlay 3 cursor 3 delete 3 Cdelete 2 down 1 duplicate " + "3 xEdit 1 expand 3 extract 3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 " + "forward 2 get help 1 hexType 4 input 1 powerInput 3 join 1 split 2 spltJOIN load " + "locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2 macro merge 2 modify 3 move 2 " + "msg next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit read recover 3 " + "refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left " + "2 save set shift 2 si sort sos stack 3 status 4 top transfer 3 type 1 up 1 "
func minOf(x, y int) int {
if x < y { return x } return y
}
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) splits := strings.Fields(table) slen := len(splits) commands := make([]string, 0, slen / 2) // capacity approximate minLens := make([]int, 0, slen / 2) // ditto i := 0 for { commands = append(commands, splits[i]) len := len(splits[i]) if i == slen - 1 { minLens = append(minLens, len) break } i++ num, err := strconv.Atoi(splits[i]) if err == nil { minLens = append(minLens, minOf(num, len)) i++ if i == slen { break } } else { minLens = append(minLens, len) } } 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
Kotlin
<lang scala>// 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()
}</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
Perl 6
Demonstrate that inputting an empty string returns an empty string in addition to the required test input.
<lang perl6>< 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;
}</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:
Python
<lang python>
command_table_text = """add 1 alter 3 backup 2 bottom 1 Cappend 2 change 1 Schange Cinsert 2 Clast 3
compress 4 copy 2 count 3 Coverlay 3 cursor 3 delete 3 Cdelete 2 down 1 duplicate 3 xEdit 1 expand 3 extract 3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 forward 2 get help 1 hexType 4 input 1 powerInput 3 join 1 split 2 spltJOIN load locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2 macro merge 2 modify 3 move 2 msg next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit read recover 3 refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left 2 save set shift 2 si sort sos stack 3 status 4 top transfer 3 type 1 up 1"""
user_words = "riG rePEAT copies put mo rest types fup. 6 poweRin"
def find_abbreviations_length(command_table_text):
""" find the minimal abbreviation length for each word. a word that does not have minimum abbreviation length specified gets it's full lengths as the minimum. """ command_table = dict() input_iter = iter(command_table_text.split())
word = None try: while True: if word is None: word = next(input_iter) abbr_len = next(input_iter, len(word)) try: command_table[word] = int(abbr_len) word = None except ValueError: command_table[word] = len(word) word = abbr_len except StopIteration: pass return command_table
def find_abbreviations(command_table):
""" for each command insert all possible abbreviations""" abbreviations = dict() for command, min_abbr_len in command_table.items(): for l in range(min_abbr_len, len(command)+1): abbr = command[:l].lower() abbreviations[abbr] = command.upper() return abbreviations
def parse_user_string(user_string, abbreviations):
user_words = [word.lower() for word in user_string.split()] commands = [abbreviations.get(user_word, "*error*") for user_word in user_words] return " ".join(commands)
command_table = find_abbreviations_length(command_table_text)
abbreviations_table = find_abbreviations(command_table)
full_words = parse_user_string(user_words, abbreviations_table)
print("user words:", user_words) print("full words:", full_words) </lang>
Racket
<lang racket>#lang racket (require srfi/13)
(define command-table #<<EOS add 1 alter 3 backup 2 bottom 1 Cappend 2 change 1 Schange Cinsert 2 Clast 3 compress 4 copy 2 count 3 Coverlay 3 cursor 3 delete 3 Cdelete 2 down 1 duplicate 3 xEdit 1 expand 3 extract 3 find 1 Nfind 2 Nfindup 6 NfUP 3 Cfind 2 findUP 3 fUP 2 forward 2 get help 1 hexType 4 input 1 powerInput 3 join 1 split 2 spltJOIN load locate 1 Clocate 2 lowerCase 3 upperCase 3 Lprefix 2 macro merge 2 modify 3 move 2 msg next 1 overlay 1 parse preserve 4 purge 3 put putD query 1 quit read recover 3 refresh renum 3 repeat 3 replace 1 Creplace 2 reset 3 restore 4 rgtLEFT right 2 left 2 save set shift 2 si sort sos stack 3 status 4 top transfer 3 type 1 up 1 EOS
)
(define command/abbr-length-pairs
(let loop ((cmd-len-list (string-split command-table)) (acc (list))) (match cmd-len-list ((list) (sort acc < #:key cdr)) ((list-rest a (app string->number (and ad (not #f))) dd) (loop dd (cons (cons a ad) acc))) ((list-rest a d) (loop d (cons (cons a (string-length a)) acc))))))
(define (validate-word w)
(or (let ((w-len (string-length w))) (for/first ((candidate command/abbr-length-pairs) #:when (and (>= w-len (cdr candidate)) (string-prefix-ci? w (car candidate)))) (string-upcase (car candidate)))) "*error*"))
(define (validate-string s) (string-join (map validate-word (string-split s))))
(module+ main
(define (debug-i/o s) (printf "input: ~s~%output: ~s~%" s (validate-string s))) (debug-i/o "") (debug-i/o "riG rePEAT copies put mo rest types fup. 6 poweRin"))
(module+ test
(require rackunit) (check-equal? (validate-string "riG rePEAT copies put mo rest types fup. 6 poweRin") "RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT") (check-equal? (validate-string "") ""))</lang>
- Output:
input: "" output: "" input: "riG rePEAT copies put mo rest types fup. 6 poweRin" output: "RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT"
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 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. */</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
zkl
<lang zkl>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();</lang>
- Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT