# Print the character names [closed]

Every Unicode character has a name, like "LATIN CAPITAL LETTER A". A Unicode character name may contain only uppercase letters, white spaces, and the minus sign.

Write a program that reads a text and outputs the names of each character on a new line. For example, if the input were "Hello, World!", the output would be

LATIN CAPITAL LETTER H
LATIN SMALL LETTER E
LATIN SMALL LETTER L
LATIN SMALL LETTER L
LATIN SMALL LETTER O
COMMA
SPACE
LATIN CAPITAL LETTER W
LATIN SMALL LETTER O
LATIN SMALL LETTER R
LATIN SMALL LETTER L
LATIN SMALL LETTER D
EXCLAMATION MARK

• Input should come from a file or from user input, not just a string in code.
• Output should be written to a file or stdout or printed to the screen.
• Internet and external libraries are not allowed, all necessary data should be in the code.
• Assume that the input only contains printable ASCII characters in the Basic Latin code range 32-126. You can ignore a trailing newline.
• All programming languages allowed. Shortest code in bytes wins.

The official Unicode character names can be found here. Other sources:

This is my first question so I'd appreciate any suggestion if this can be improved.

For the purpose of this challenge the list below shall be normative.

    32  0020        SPACE
!   33  0021        EXCLAMATION MARK
"   34  0022        QUOTATION MARK
#   35  0023        NUMBER SIGN
$36 0024 DOLLAR SIGN % 37 0025 PERCENT SIGN & 38 0026 AMPERSAND ' 39 0027 APOSTROPHE ( 40 0028 LEFT PARENTHESIS ) 41 0029 RIGHT PARENTHESIS * 42 002A ASTERISK + 43 002B PLUS SIGN , 44 002C COMMA - 45 002D HYPHEN-MINUS . 46 002E FULL STOP / 47 002F SOLIDUS 0 48 0030 DIGIT ZERO 1 49 0031 DIGIT ONE 2 50 0032 DIGIT TWO 3 51 0033 DIGIT THREE 4 52 0034 DIGIT FOUR 5 53 0035 DIGIT FIVE 6 54 0036 DIGIT SIX 7 55 0037 DIGIT SEVEN 8 56 0038 DIGIT EIGHT 9 57 0039 DIGIT NINE : 58 003A COLON ; 59 003B SEMICOLON < 60 003C LESS-THAN SIGN = 61 003D EQUALS SIGN > 62 003E GREATER-THAN SIGN ? 63 003F QUESTION MARK @ 64 0040 COMMERCIAL AT A 65 0041 LATIN CAPITAL LETTER A B 66 0042 LATIN CAPITAL LETTER B C 67 0043 LATIN CAPITAL LETTER C D 68 0044 LATIN CAPITAL LETTER D E 69 0045 LATIN CAPITAL LETTER E F 70 0046 LATIN CAPITAL LETTER F G 71 0047 LATIN CAPITAL LETTER G H 72 0048 LATIN CAPITAL LETTER H I 73 0049 LATIN CAPITAL LETTER I J 74 004A LATIN CAPITAL LETTER J K 75 004B LATIN CAPITAL LETTER K L 76 004C LATIN CAPITAL LETTER L M 77 004D LATIN CAPITAL LETTER M N 78 004E LATIN CAPITAL LETTER N O 79 004F LATIN CAPITAL LETTER O P 80 0050 LATIN CAPITAL LETTER P Q 81 0051 LATIN CAPITAL LETTER Q R 82 0052 LATIN CAPITAL LETTER R S 83 0053 LATIN CAPITAL LETTER S T 84 0054 LATIN CAPITAL LETTER T U 85 0055 LATIN CAPITAL LETTER U V 86 0056 LATIN CAPITAL LETTER V W 87 0057 LATIN CAPITAL LETTER W X 88 0058 LATIN CAPITAL LETTER X Y 89 0059 LATIN CAPITAL LETTER Y Z 90 005A LATIN CAPITAL LETTER Z [ 91 005B LEFT SQUARE BRACKET \ 92 005C REVERSE SOLIDUS ] 93 005D RIGHT SQUARE BRACKET ^ 94 005E CIRCUMFLEX ACCENT _ 95 005F LOW LINE  96 0060 GRAVE ACCENT a 97 0061 LATIN SMALL LETTER A b 98 0062 LATIN SMALL LETTER B c 99 0063 LATIN SMALL LETTER C d 100 0064 LATIN SMALL LETTER D e 101 0065 LATIN SMALL LETTER E f 102 0066 LATIN SMALL LETTER F g 103 0067 LATIN SMALL LETTER G h 104 0068 LATIN SMALL LETTER H i 105 0069 LATIN SMALL LETTER I j 106 006A LATIN SMALL LETTER J k 107 006B LATIN SMALL LETTER K l 108 006C LATIN SMALL LETTER L m 109 006D LATIN SMALL LETTER M n 110 006E LATIN SMALL LETTER N o 111 006F LATIN SMALL LETTER O p 112 0070 LATIN SMALL LETTER P q 113 0071 LATIN SMALL LETTER Q r 114 0072 LATIN SMALL LETTER R s 115 0073 LATIN SMALL LETTER S t 116 0074 LATIN SMALL LETTER T u 117 0075 LATIN SMALL LETTER U v 118 0076 LATIN SMALL LETTER V w 119 0077 LATIN SMALL LETTER W x 120 0078 LATIN SMALL LETTER X y 121 0079 LATIN SMALL LETTER Y z 122 007A LATIN SMALL LETTER Z { 123 007B LEFT CURLY BRACKET | 124 007C VERTICAL LINE } 125 007D RIGHT CURLY BRACKET ~ 126 007E TILDE  • Hi, I've gone ahead and edited your question, roll back if you disagree. You don't need more sources of the information, you need one, normative version in the question, to avoid issues with discrepancies. I picked ssec.wisc.edu/~tomw/java/unicode.html#x0000 as it was the most concise. Other than that, +1 Sep 6, 2015 at 15:21 • Thanks for the edit @steveverrill, I was too lazy to do that myself. Sep 6, 2015 at 15:26 • Apparently the values are available as part of Windows, in C:\Windows\System32\getuname.dll. Does this also count as an "external library", even if it's built in to Windows? – lc. Sep 7, 2015 at 12:18 • I just learned the word solidus. – Luke Sep 23, 2015 at 18:20 • I’m voting to close this question because, as discussed in chat here, it's unclear what exactly constitutes an "external library". Mar 15 at 15:39 ## 19 Answers # Java - 113 bytes (152 if read from command line) Edit: removed useless curly brackets. Edit2: removed unnecessary variable. Edit3: Instead of Character.getName() I use c.getName(). Edit4: Passing string as command line argument. With command line argument (113 bytes): class Z{public static void main(String[]x){for(Character c:x[0].toCharArray())System.out.println(c.getName(c));}}  With read line (152 bytes): class Z{public static void main(String[]x){for(Character c:new java.util.Scanner(System.in).nextLine().toCharArray())System.out.println(c.getName(c));}}  Java has everything needed. I'm sure this could be golfed down. • Damn! A builtin! In order to make this an interesting challenge, I would consider this to be in non-compliance with "all necessary data should be in the code." Very clever, though. Sep 6, 2015 at 15:35 • @steveverrill Oh well :) . I've seen another challenge where common lisp did something similar (counting from one to 100 if I remember right). Sep 6, 2015 at 15:41 • Wow, this time Java has the chance to beat a lot of golfing languages. – vsz Sep 6, 2015 at 19:47 • Alternative Java 8 solution: x[0].chars().forEach(i->System.out.println(Character.getName(i))); This saves 2 chars compared to the command-line argument solution (by replacing the for-loop). Sep 7, 2015 at 7:05 • Or maybe x[0].chars().map(' '::getName).forEach(System.out::println); – Eric Sep 8, 2015 at 18:26 # Python 3, 56 bytes Uses a built-in function unicodedata.name(), so this may be non-competent. The Java answer did it similarly, so I thought it was at least worth posting. from unicodedata import* for i in input():print(name(i))  • I've also wanted to post one in python but my java answer was cheaty enough :) . Sep 6, 2015 at 18:56 • Surely for i in input():print(unicodedata.name(i)) is shorter? – Eric Sep 8, 2015 at 4:01 • @Eric No. You have to import unicodedata, so that's longer. Sep 8, 2015 at 13:24 • Same length using lambda+map Jul 6, 2021 at 3:04 # JavaScript (ES6) 594 618 626 Note I could save ~30 bytes compressing the long string with atob/btoa, but the utf8 character above '~' are not well accepted by the Stack Exchange post editor. I prefer to keep a running snippet instead. Edit 8 chars saved thx @Ypnypn Obvious compression of repeated words. The newline inside backticks is significant and counted. Test running the snippet in Firefox. // TEST SUITE // for testing purpose, redefine alert() to write inside the snippet body alert=x=>O.innerHTML=x // for testing purpose, redefine prompt() to have a default text containing all characters _prompt=prompt prompt=(i,s)=>{ for(s='',i=32;i<127;i++)s+=String.fromCharCode(i); return _prompt("Insert your message or keep the default",s); } // That's the answer code: z='SPACE/EXCLAMA0QUOTA0NUMBER1DOLLAR1PERCENT1AMPERSAND/APOSTROPHE3242ASTERISK/PLUS1COMMA/HYPHEN-MINUS/FULL STOP/78ZERO8ONE8TWO8THREE8FOUR8FIVE8SIX8SEVEN8EIGHT8NINE86SEMI6LESS-THAN1EQUALS1GREATER-THAN1QUES0COMMERCIAL AT3SQUARE5REVERSE 7/4SQUARE5CIRCUMFLEX9/LOW LINE/GRAVE93CURLY5VERTICAL LINE/4CURLY5TILDE'.replace(/\d/g,c=>'TION MARK/, SIGN/,PARENTHESIS/,/LEFT ,RIGHT , BRACKET/,COLON/,SOLIDUS,/DIGIT , ACCENT'.split,[c]).split/,alert([...prompt()].map(c=>(q=c.charCodeAt()-32)<33?z[q]:q<59?'LATIN CAPITAL LETTER '+c:q<65?z[q-26]:q<91?'LATIN SMALL LETTER '+c.toUpperCase():z[q-52]).join ) <pre id=O></pre> # R, 54 bytes 62 library(Unicode) cat(u_char_name(utf8ToInt(scan(,""))),sep="\n")  Edit: per @flodels comment, I need to read it from connection first, so had to add scan. This is also probably non-competent solution according to all the rules. Usage > cat(u_char_name(utf8ToInt(scan(,""))),sep="\n") 1: 'Hello, World!' 2: Read 1 item LATIN CAPITAL LETTER H LATIN SMALL LETTER E LATIN SMALL LETTER L LATIN SMALL LETTER L LATIN SMALL LETTER O COMMA SPACE LATIN CAPITAL LETTER W LATIN SMALL LETTER O LATIN SMALL LETTER R LATIN SMALL LETTER L LATIN SMALL LETTER D EXCLAMATION MARK  You can also wrap it up into a function for more convenient usage UNI <- function(x)cat(paste0(u_char_name(utf8ToInt(x)),"\n"))  Then, the usage is just UNI("Hello, World!")  • Your byte count is correct :) Sep 7, 2015 at 9:03 • And welcome to PPCG! :D Sep 7, 2015 at 9:03 • Good for you having a built in for the task, but the output is not what is requested - 4 columns table instead of 1 column table. I think you should add some core to obtain the correct output Sep 7, 2015 at 9:25 • @edc65 that easy to fix, I just thought of it as a bonus. Sep 7, 2015 at 9:30 • @edc65 fixed it. Sep 7, 2015 at 9:37 # C, 644 656 Full program, reading from standard input Test on Ideone This is a porting of my JavaScript answer to C. The C language is good at manipulating single characters as numbers (no need of .toUpperCase and the like), but it's weaker in string manipulation. char*s,*p,*q,b[999],*d=b+99,c,*l[129]; main(k){for(k=32,p="/SPACE/EXCLAMAaQUOTAaNUMBERbDOLLARbPERCENTbAMPERSAND/APOSTROPHEdcecASTERISK/PLUSbCOMMA/HYPHEN-MINUS/FULL STOP/hiZEROiONEiTWOiTHREEiFOURiFIVEiSIXiSEVENiEIGHTiNINE/gSEMIgLESSnbEQUALSbGREATERnbQUESaCOMMERCIAL ATdkfREVERSE h/ekfCIRCUMFLEXj/LOWmGRAVEjdlfVERTICALmelfTILDE/"; c=*p;p++)c>96?q?(p=q,q=0):(q=p,p=strchr("aTION MARK/b SIGN/cPARENTHESIS/d/LEFT eRIGHT f BRACKET/gCOLON/hSOLIDUSi/DIGIT j ACCENTkSQUARElCURLYm LINE/n-THANz",c)):c-47?*d++=c:(*d++=0,l[k++]=d); for(;~(k=getchar());puts(k<65?l[k]:(k&31)<27?b:l[k<97?k-26:k-52]))sprintf(b,"LATIN %s LETTER %c",k<91?"CAPITAL":"SMALL",k&95);}  Less golfed char *all = "/SPACE/EXCLAMAaQUOTAaNUMBERbDOLLARbPERCENTbAMPERSAND/APOSTROPHEdcecASTERISK/PLUSbCOMMA/HYPHEN-MINUS/FULL STOP/hiZEROiONEiTWOiTHREEiFOURiFIVEiSIXiSEVENiEIGHTiNINE/gSEMIgLESSnbEQUALSbGREATERnbQUESaCOMMERCIAL ATdkfREVERSE h/ekfCIRCUMFLEXj/LOWmGRAVEjdlfVERTICALmelfTILDE/"; char *subs = "aTION MARK/b SIGN/cPARENTHESIS/d/LEFT eRIGHT f BRACKET/gCOLON/hSOLIDUSi/DIGIT j ACCENTkSQUARElCURLYm LINE/n-THANz"; main(int k) { char c, *s, *p, *q=0, b[999], // work buffer *d = b+99, // first part of buffer is used later *l[129]; // characters descriptions (used 32 to 126) // Uncompress the descriptions of all char except letters for(k = 32, p = all; c = *p; ++p) { c >= 'a' // substitution word are marked as lowercase letters ? q ? (p = q, q = 0) : (q = p, p = strchr(subs, c)) : c != '/' ? *d++ = c : (*d++ = 0, l[k++] = d); // end char description } // Scan the input string and print each char description for(; (k=getchar()) != -1; ) { sprintf(b,"LATIN %s LETTER %c", k<91 ? "CAPITAL":"SMALL", k & 95); puts( k<65 ? l[k] : k<91 ? b : k<97 ? l[k-26] : k<123 ? b : l[k-52]); } }  # Perl 6, 21 bytes I did not see a rule specifically against using a built-in method for getting the unicode names. (Also the Java answer which is the currently highest voted one does the same) .say for get.uninames  • Perl 6 is weird. I love it, though. – cat Apr 30, 2016 at 15:30 # Perl 5 + -M5.10.0 -MCompress::Zlib -00F, 459 bytes @d=split/,/,inflateInit->inflate(<DATA>);say$d[-32+ord]for@F
__END__
x.m.or.0.......!.#....I&I.......v......0O.)q.g.*...PH.q....u..k...85.:sgM\.8P..Fu......r..=tR...e......9k.{.2.xUj.P\_}..Qr...!..[..$O.2.%{.bmgl.....|U.tnC...K-?..;.3..1.\s......K>.....T..y.$v.E.....6.....JaM.$.G!.5$...A..5.....y...g....s.....Y0...s..1o...av.............;..)..R..G...8..t...K)k.e.~.J..Gi. .r\.v>.........!L.'..pF. \.f......aAX.6....P..BG8......._..
....W...s"9.t....
.2......


Try it online!

## Explanation

Pretty straight-forward, @d is constructed from Zlib compressed data (stored after __END__), which is just the compressed list of raw comma separated character names that is inflated, split on , and can be indexed via ord - 32. -00 sets the input record separator to \x00 (NUL) which slurps the __DATA__ in one call to <DATA> instead of having it split on newline. @F is initialised with the input data as an array (via -F), which is iterated over and the corresponding index from @d is output.

# Perl 5 + -M5.10.0 -F, 672 bytes

printf(z=w[d[q[i]]-69])" "(z~/TT/?toupper($k):_) }  # C++11, 739 bytes #include<iostream> #define D,"DIGIT " #define G" SIGN", int main(){std::string a=" BRACKET",s="SQUARE"+a,c="CURLY"+a,t="TION MARK",p="PARENTHESIS",l="LEFT ",r="RIGHT ",x="LATIN ",y="L LETTER ",z[]{"SPACE","EXCLAMA"+t,"QUOTA"+t,"NUMBER"G"DOLLAR"G"PERCENT"G"AMPERSAND","APOSTROPHE",l+p,r+p,"ASTERISK","PLUS"G"COMMA","HYPHEN-MINUS","FULL STOP","SOLIDUS"D"ZERO"D"ONE"D"TWO"D"THREE"D"FOUR"D"FIVE"D"SIX"D"SEVEN"D"EIGHT"D"NINE","COLON","SEMICOLON","LESS-THAN"G"EQUALS"G"GREATER-THAN"G"QUES"+t,"COMMERCIAL AT",l+s,"REVERSE SOLIDUS",r+s,"CIRCUMFLEX ACCENT","LOW LINE","GRAVE ACCENT",l+c,"VERTICAL LINE",r+c,"TILDE"};getline(std::cin,s);for(char c:s)std::cout<<(c<65?z[c-32]:c<91?x+"CAPITA"+y+c:(c-=32,c<65?z[c-26]:c<91?x+"SMAL"+y+c:z[c-52]))+"\n";}  Based on sweerpotato's solution, but modified heavily. • Nicely done :~)! Sep 8, 2015 at 19:36 # Common Lisp (SBCL), 52 79 (map()(lambda(y)(format t"~:@(~A~)~%"(substitute #\ #\_(char-name y))))(read))  This is built-in and implementation-dependent, so you may want to ignore it when choosing the accepted answer. This is not enough to beat Python, unfortunately. The updated version conforms to the expected output (I have to replace underscores by spaces). ## Example CL-USER> (map()(lambda(y)(format t"~:@(~A~)~%"(substitute #\ #\_(char-name y))))(read)) "(λ(r)(* 2 ᴨ r))" LEFT PARENTHESIS GREEK SMALL LETTER LAMDA LEFT PARENTHESIS LATIN SMALL LETTER R RIGHT PARENTHESIS LEFT PARENTHESIS ASTERISK SPACE DIGIT TWO SPACE GREEK LETTER SMALL CAPITAL PI SPACE LATIN SMALL LETTER R RIGHT PARENTHESIS RIGHT PARENTHESIS  ## C++14, 10431000998996 972 bytes Grotesque solution in C++14: #include<iostream> #include<map> #define b cout #define d string #define e },{ using namespace std;char l='\n';d s[]{"DIGIT ","LATIN CAPITAL LETTER ","LATIN SMALL LETTER "};map<char, d> m{{' ',"SPACE"e'!',"EXCLAMATION MARK"e'\"',"QUOTATION MARK"e'#',"NUMBER SIGN"e'$',"DOLLAR SIGN"e'%',"PERCENT SIGN"e'&',"AMPERSAND"e'\'',"APOSTROPHE"e'(',"LEFT PARENTHESIS"e')',"RIGHT PARENTHESIS"e'*',"ASTERISK"e'+',"PLUS SIGN"e',',"COMMA"e'-',"HYPHEN-MINUS"e'.',"FULL STOP"e'/',"SOLIDUS"e':',"COLON"e';',"SEMICOLON"e'<',"LESS-THAN SIGN"e'=',"EQUALS SIGN"e'>',"GREATER-THAN SIGN"e'?',"QUESTION MARK"e'@',"COMMERCIAL AT"e'[',"LEFT SQUARE BRACKET"e'\\',"REVERSE SOLIDUS"e']',"RIGHT SQUARE BRACKET"e'^',"CIRCUMFLEX ACCENT"e'_',"LOW LINE"e'',"GRAVE ACCENT"e'{',"LEFT CURLY BRACKET"e'|',"VERTICAL LINE"e'}',"RIGHT CURLY BRACKET"e'~',"TILDE"}};int main(){d str;getline(cin,str);for(char c:str){islower(c)?b<<s[2]<<(char)(c-32):isupper(c)?b<<s[1]<<c:isdigit(c)?b<<*s<<c:b<<m.at(c);b<<l;}}


Thanks to kirbyfan64sos for golfing off two bytes

• Can you do *s instead of s[0]? Sep 7, 2015 at 23:41
• Sure can! Totally missed that Sep 8, 2015 at 19:04

# Pyth, 41

$from unicodedata import name as neg$Vz_N


Uses same builtin as mbomb007's python answer. Note that this cannot be executed online because the $ operator is unsafe. # CJam, 517 l{i32-["SPACE""EXCLAMA""TION MARK":T+"QUOTA"T+"NUMBER DOLLAR PERCENT"{S/" SIGN"am*~}:H~"AMPERSAND""APOSTROPHE""LEFT PARENTHESIS":L"RIGHT ":R1$5>+"ASTERISK""PLUS"H"COMMA""HYPHEN-MINUS""FULL STOP""SOLIDUS":D"DIGIT "a"ZERO ONE TWO THREE FOUR FIVE SIX SEVEN EIGHT NINE"S/m*~"COLON""SEMI"1$+"LESS-THAN EQUALS GREATER-THAN"H"QUES"T+"COMMERCIAL AT""CAPITA"{["LATIN "\"L LETTER "]a'[,65>m*~L5<}:Z~"SQUARE BRACKET":Q+"REVERSE "D+RQ+"CIRCUMFLEX ACCENT""LOW LINE""GRAVE"2$A>+"SMAL"Z"CURLY"33$B>+:C+"VERTICAL LINE"RC+"TILDE"]=N}/  Online version I have tried different solutions but simply storing all the names in a huge array seems most efficient. This is my first real CJam program by the way. # Clojure, 56 bytes (doseq[c(read-line)](println(Character/getName(int c))))  Inspired by @peter's answer. Uses Clojure for the Java interop. # Perl - 894 bytes Lovingly crafted by hand. First time golfing in Perl so any tips are appreciated. $_=$ARGV[0];s/(.)/$1\n/g;s/([A-Z])/& CAPITAL' $1/g;s/([a-z])/& SMALL' \U$1/g;s/,/COMMA/g;s/& /LATIN /g;s/' / LETT, /g;s/&/AMP,SAND/g;s/'/APOSTROPHE/g;s/ \n/SPACE\n/g;s/\*/AST,ISK/g;s/-/HYPHEN-MINUS/g;s/\./FULL STOP/g;s/@/COMM,CIAL AT/g;s/~/TILDE/g;s/:/&/g;s/;/SEMI&/g;s/&/COLON/g;s/\|/V,TICAL&/g;s/_/LOW&/g;s/&/ LINE/g;s/\^/CIRCUMFLEX&/g;s//GRAVE&/g;s/&/ ACCENT/g;s/\//&/g;s/\\/REV,SE &/g;s/&/SOLIDUS/g;s/!/!&/g;s/"/"&/g;s/\?/?&/g;s/!/EXCLAMA/g;s/"/QUOTA/g;s/\?/QUES/g;s/&/TION MARK/g;s/#/NUMB,&/g;s/$/DOLLAR&/g;s/%/P,CENT&/g;s/\+/PLUS&/g;s/</LESS-THAN&/g;s/=/EQUALS&/g;s/>/GREAT,-THAN&/g;s/&/ SIGN/g;s/$$/<&/g;s/$$/>&/g;s/&/ PARENTHESIS/g;s/$/<&/g;s/$/>&/g;s/&/ SQUARE'/g;s/{/<&/g;s/}/>&/g;s/&/ CURLY'/g;s/'/ BRACKET/g;s/</LEFT/g;s/>/RIGHT/g;s/0/&Z,O/g;s/1/&ONE/g;s/2/&TWO/g;s/3/&THREE/g;s/4/&FOUR/g;s/5/&FIVE/g;s/6/&SIX/g;s/7/&SEVEN/g;s/8/&EIGHT/g;s/9/&NINE/g;s/&/DIGIT /g;s/,/ER/g;print;  ## C++14 716706 704 #include<iostream> char*q,x,b[584],*t=b,a[]=R"(space}exclamation|mark}quot"-number|sign}dolla!apercent!mam"%sand}apostrophe}left|par%3hesis}righ"Wasterisk}plus*<comma}hy)#n{minus}full|stop}solid"Ldigit|zero!Tone!Gtw"kthre#&four!Uiv#&six!Heve>^!_e6r!ani,1colon}semi!Fless{than8Eequal:grea<s2quesMj>EJoial|at}lQ9n|capit"?let('|Jes+\re|bracket}r5urse|C5M?%2circumflex|acXR}low|l:bgrave#'0=smaNy0+curly*s/Ytic4z)/$itilde)",*s=a;int c,z,l='{';int main(){for(;x=*s++;)if(z=x-32,x>96)*t++=x<l?z:"- "[x%l];else for(c=z*95+*s++-32,q=t-c/13,x=3+c%13;x--;)*t++=*q++;while(std::cin.get(x)){for(s=b,z=0,c=x<65?x-32:x<91?z=33:x<97?x-57:x<l?z=40:x-82;c--;)while(*s++);auto&o=std::cout<<s;(z?o.put(x&~32):o)<<"\n";}}


With some whitespace:

#include <iostream>

// a is compressed using an LZ like compression scheme
char *q, x, b[584],
*t = b,
a[] =
R"(space}exclamation|mark}quot"-number|sign}dolla!apercent!mam"%sand}apostrophe}left|par%3hesis}righ"Wasterisk}plus*<comma}hy)#n{minus}full|stop}solid"Ldigit|zero!Tone!Gtw"kthre#&four!Uiv#&six!Heve>^!_e6r!ani,1colon}semi!Fless{than8Eequal:$grea<s$2quesMj>EJoial|at}lQ9n|capit"?let('|Jes+\re|bracket}r5urse|C5M?%2circumflex|acXR}low|l:bgrave#'0=smaNy0+curly*s/Ytic4z)$/\$itilde)",
*s = a;

int c, z, l = '{';

int main() {
// Decompress from a into b
for (; x = *s++;)
if (z = x - 32, x > 96)
*t++ = x < l ? z : "- "[x % l];
else
for (c = z * 95 + *s++ - 32, q = t - c / 13, x = 3 + c % 13; x--;) *t++ = *q++;

// Process input a char at a time, performing a lookup into b for the c'th null separated string
while (std::cin.get(x)) {
for (s = b, z = 0,
c = x < 65 ? x - 32 : x < 91 ? z = 33 : x < 97 ? x - 57 : x < l ? z = 40 : x - 82;
c--;)
while (*s++)
;
auto& o = std::cout << s;
(z ? o.put(x & ~32) : o) << "\n";
}
}


The compressed string a decompresses to:

space}exclamation|mark}quotation|mark}number|sign}dollar|sign}percent|sign}ampersand}apostrophe}left|parenthesis}right|parenthesis}asterisk}plus|sign}comma}hyphen{minus}full|stop}solidus}digit|zero}digit|one}digit|two}digit|three}digit|four}digit|five}digit|six}digit|seven}digit|eight}digit|nine}colon}semicolon}less{than|sign}equals|sign}greater{than|sign}question|mark}commercial|at}latin|capital|letter|}left|square|bracket}reverse|solidus}right|square|bracket}circumflex|accent}low|line}grave|accent}latin|small|letter|}left|curly|bracket}vertical|line}right|curly|bracket}tilde

And during decompression } is replaced with \0, | with   (space) and { with - and lowercase letters are converted to uppercase.

The string is compressed LZ style as either a literal [a-~] or a two character encoded offset/length to a match earlier in the string.

# Factor, 58 bytes

[ readln [ char>name "-"" " replace >upper print ] each ]


Pretty simple; does the exact same thing as the Java and Perl 6 answers.

# Go, 145 bytes

package main
import(."golang.org/x/text/unicode/runenames"
."fmt")
func main(){r:='!'
for{_,e:=Scanf("%c",&r)
if e!=nil{break}
println(Name(r))}}


Some have address a concern with the above answer. I tried vendoring the code in question, but my answer bypassed the 65,536 byte limit [1], so I think the above answer is fine as is.

• From the question, Internet and external libraries are not allowed, all necessary data should be in the code.
– Jo King
Jul 6, 2021 at 3:33
• When I run code myself, it says cannot find package "golang.org/x/text/unicode/runenames" in any of: /usr/lib/golang/src/golang.org/x/text/unicode/runenames (from $GOROOT) /home/runner/go/src/golang.org/x/text/unicode/runenames (from$GOPATH)
– Jo King
Jul 6, 2021 at 4:18
• But it is my job to make sure that answers comply with the spirit and letter of the challenge. This runenames import appears to be an external library, which is disallowed.
– Jo King
Jul 6, 2021 at 13:07
• Whether JoKing is a moderator or not is irrelevant here - any user should be able to check if an answer is valid by the rules. Obviously, not everyone is familiar with Go, so it is up to you to demonstrate that your answer follows all rules, including "Internet and external libraries are not allowed" If this answer requires the internet to work, then it isn't valid per the question. It'd be helpful if you could verify this or not, as you clearly know more about Go than either me or JoKing Jul 6, 2021 at 14:12
• discussion in chat starting here Jul 6, 2021 at 14:21

# PHP>=7, 54 Bytes

for(;a&$c=$argn[$i++];)echo" ".IntlChar::charName($c);
`

IntlChar::charName