Abbreviations, easy

From Rosetta Code
Abbreviations, easy 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.

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


Related tasks



ALGOL 68[edit]

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

Uses Algol 68G specific is lower and to upper procedures. Does not use a hash table.

# "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 )
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:

Factor[edit]

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 ] [email protected] start 0 = ;
: capitals ( str -- n ) [ LETTER? ] count ;
: min-len? ( candidate command -- ? ) capitals swap length <= ;
: not-longer? ( candidate command -- ? ) [ length ] [email protected] <= ;
: permitted? ( candidate command -- ? ) dup [ letter? ] count 0
> [ [ >upper ] [email protected] = ] 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 ] [email protected]
[ "User words: " write print ]
[ "Full words: " write print ] bi* ;
 
: main ( -- ) user-input "" [ .abbr ] [email protected] ;
 
MAIN: main
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[edit]

Translation of: Kotlin
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, " "))
}
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

Julia[edit]

Works with: Julia version 0.6
Translation of: Kotlin
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)))
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[edit]

// 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()
}
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[edit]

Translation of: Perl 6
@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"
Output:
Input:              riG       rePEAT    copies    put       mo        rest      types     fup.      6         poweRin
Output:             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 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.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;
}
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[edit]

Works with: Python version 3.6
 
 
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 lengths 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)
 

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 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. */
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]

Rather more brute force than I'd like but hashing the command table is just too much code. And the table is so small...

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();
Output:
RIGHT REPEAT *error* PUT MOVE RESTORE *error* *error* *error* POWERINPUT