Expandably change letter case and use inside \csname, without a package

If you know that the input consists only of characters with category code 11 or 12 (or maybe others, but definitely not control sequences), a less horrible hack is

\def\explowerchar#1{%
  \ifcase\numexpr`#1-`A\relax
   a\or b\or c\or d\or e\or f\or g\or h\or i\or j\or k\or l\or m\or
   n\or o\or p\or q\or r\or s\or t\or u\or v\or w\or x\or y\or z\else
   #1\fi
}

\def\explower#1{%
  \doexplowerchar#1\relax
}

\def\doexplowerchar#1{%
  \ifx#1\relax
  \else
    \explowerchar{#1}\expandafter\doexplowerchar
  \fi
}

\edef\lcstring{\explower{AStRiNg?}}
\show\lcstring

Output on the terminal:

> \lcstring=macro:
->astring?.

Needs e-TeX, of course.

There's no way of doing \lowercase expandably in full generality, I'm afraid.

Without reinventing the wheel:

\documentclass{article}
\usepackage{expl3}

\ExplSyntaxOn
\cs_set_eq:NN \explower \text_lowercase:n
\ExplSyntaxOff

\edef\lcstring{\explower{A StRiNg wiTh SpaC\'Es?}}
\show\lcstring

Terminal output:

> \lcstring=macro:
->astring with spac\'es?.

I know you've asked for a package-free solution, but for reference the following the the approach we are likely to take to this problem in expl3. The 'design brief' here is that case folding (as defined by the Unicode people) should take place to leave 'caseless' data. Clearly this is only fully doable for LuaTeX/XeTeX: the 'fall back' for pdfTeX is to restrict the data used to only ASCII letters. Note that the code here is from Bruno: I tried a simpler approach but the following is more elegant and much faster!


The concept of string case folding is now available in expl3 as \str_foldcase:n as described by the 'design brief' above. For constructing csnames, where case changing may be required, there are also \str_uppercase:n and \str_lowercase:n. Note these are separate from text case changing, also available in and expandable manner in expl3.


Original code (before addition to expl3): note the the current implementation creates the stored data dynamically from UnicodeData.txt and related source files.

The 'business end' of the approach is a set up (using expl3 syntax):

\cs_new:Npn \str_fold_case:n #1
  {
    \exp_after:wN \__str_fold_auxi:w \tl_to_str:n {#1}
    { ~ \c_empty_tl } \__str_fold_end:w ? ~
  }
\cs_new:Npn \__str_fold_auxi:w #1 ~
  {
    \__str_fold_auxii:N #1 { ~ \c_space_tl }
    \__str_fold_auxi:w
  }
\cs_new:Npn \__str_fold_auxii:N #1
  {
    \exp_after:wN \__str_fold_auxiii:NNNNNNNN
    \int_use:N \__int_eval:w 1000000 + `#1 \__int_eval_end: #1
  }
\cs_new:Npn \__str_fold_auxiii:NNNNNNNN #1#2#3#4#5#6#7#8
  {
    \exp_args:NNv \str_case_x:nnF #8
      { c__str_case_#6_X_#7_tl }
      { #8 \exp_after:wN \use_none:n #8 }
    \__str_fold_auxii:N
  }
\cs_new:Npn \__str_fold_end:w ? #1 \__str_fold_auxi:w { }

which is therefore ultimately dependent on \pdfstrcmp (hidden inside \str_case_x:nnF) to do a string comparison. The above also needs data: this can be auto-generated from the Unicode case-folding file and currently comes out as:

\tl_const:cn {c__str_case_0_X_0_tl} {ÈèĬĭƐɛǴǵϨϩҰұԔԕḔḕṸṹỜờᾤ{ὤι}ⒸⓒⰤⱔⲈⲉꙨꙩ}
\tl_const:cn {c__str_case_0_X_1_tl} {ÉéƑƒჍⴭᾥ{ὥι}ⒹⓓⰥⱕⳭⳮ}
\tl_const:cn {c__str_case_0_X_2_tl} {ÊêĮįǶƕΆάϪϫҲҳԖԗḖḗṺṻỞởᾦ{ὦι}ⒺⓔⰦⱖⲊⲋꙪꙫꜲꜳ}
\tl_const:cn {c__str_case_0_X_3_tl} {ËëƓɠǷƿᾧ{ὧι}ⒻⓕⰧⱗ}
\tl_const:cn {c__str_case_0_X_4_tl} {Ììİ{i̇}ƔɣǸǹΈέϬϭҴҵԘԙḘḙṼṽỠỡᾨ{ὠι}ⒼⓖⰨⱘⲌⲍꙬꙭꜴꜵ}
\tl_const:cn {c__str_case_0_X_5_tl} {ÍíΉήᾩ{ὡι}ⒽⓗⰩⱙ}
\tl_const:cn {c__str_case_0_X_6_tl} {ÎîIJijƖɩǺǻΊίϮϯҶҷԚԛḚḛṾṿỢợᾪ{ὢι}ⒾⓘⰪⱚⲎⲏⳲⳳꜶꜷ}
\tl_const:cn {c__str_case_0_X_7_tl} {ÏïƗɨᾫ{ὣι}ⒿⓙⰫⱛ}
\tl_const:cn {c__str_case_0_X_8_tl} {ÐðĴĵƘƙǼǽΌόϰκҸҹԜԝḜḝẀẁỤụὈὀᾬ{ὤι}ⓀⓚⰬⱜⲐⲑꜸꜹ}
\tl_const:cn {c__str_case_0_X_9_tl} {ÑñϱρὉὁᾭ{ὥι}ⓁⓛⰭⱝ}
\tl_const:cn {c__str_case_1_X_0_tl} {ÒòĶķǾǿΎύҺһԞԟḞḟẂẃỦủὊὂᾮ{ὦι}ⓂⓜⰮⱞⲒⲓꜺꜻ}
\tl_const:cn {c__str_case_1_X_1_tl} {ÓóΏώὋὃᾯ{ὧι}Ⓝⓝ}
\tl_const:cn {c__str_case_1_X_2_tl} {ÔôƜɯȀȁΐ{ΐ}ϴθҼҽԠԡḠḡẄẅỨứὌὄⓄⓞⲔⲕꜼꜽꞠꞡ}
\tl_const:cn {c__str_case_1_X_3_tl} {ÕõĹĺƝɲΑαϵεὍὅⓅⓟAa}
\tl_const:cn {c__str_case_1_X_4_tl} {ÖöȂȃΒβҾҿԢԣḢḣẆẇỪừᾲ{ὰι}ⓆⓠⲖⲗꜾꜿꞢꞣBb}
\tl_const:cn {c__str_case_1_X_5_tl} {ĻļƟɵΓγϷϸև{եւ}ᾳ{αι}ⓇⓡCc}
\tl_const:cn {c__str_case_1_X_6_tl} {ØøƠơȄȅΔδӀӏԤԥḤḥẈẉỬửὐ{ὐ}ᾴ{άι}ⓈⓢⲘⲙꝀꝁꞤꞥDd}
\tl_const:cn {c__str_case_1_X_7_tl} {ÙùĽľΕεϹϲӁӂⓉⓣEe}
\tl_const:cn {c__str_case_1_X_8_tl} {ÚúƢƣȆȇΖζϺϻԦԧḦḧẊẋỮữὒ{ὒ}ᾶ{ᾶ}ⓊⓤⲚⲛꝂꝃꞦꞧFf}
\tl_const:cn {c__str_case_1_X_9_tl} {ÛûĿŀΗηӃӄᾷ{ᾶι}ⓋⓥGg}
\tl_const:cn {c__str_case_2_X_0_tl} {ÜüƤƥȈȉΘθѠѡḨḩẌẍỰựὔ{ὔ}ᾸᾰⓌⓦⲜⲝꝄꝅꞨꞩHh}
\tl_const:cn {c__str_case_2_X_1_tl} {ÝýŁłΙιϽͻӅӆᾹᾱⓍⓧIi}
\tl_const:cn {c__str_case_2_X_2_tl} {ÞþƦʀȊȋΚκϾͼѢѣḪḫẎẏỲỳὖ{ὖ}ᾺὰⓎⓨⲞⲟꝆꝇꞪɦJj}
\tl_const:cn {c__str_case_2_X_3_tl} {ß{ss}ŃńƧƨΛλϿͽӇӈΆάⓏⓩKk}
\tl_const:cn {c__str_case_2_X_4_tl} {ȌȍΜμЀѐѤѥḬḭẐẑỴỵᾼ{αι}ⲠⲡꚀꚁꝈꝉLl}
\tl_const:cn {c__str_case_2_X_5_tl} {ŅņƩʃΝνЁёӉӊὙὑMm}
\tl_const:cn {c__str_case_2_X_6_tl} {ȎȏΞξЂђѦѧḮḯẒẓỶỷιιⲢⲣꚂꚃꝊꝋNn}
\tl_const:cn {c__str_case_2_X_7_tl} {ŇňΟοЃѓӋӌὛὓOo}
\tl_const:cn {c__str_case_2_X_8_tl} {ƬƭȐȑΠπЄєѨѩḰḱẔẕỸỹⲤⲥꚄꚅꝌꝍPp}
\tl_const:cn {c__str_case_2_X_9_tl} {ʼn{ʼn}ΡρЅѕӍӎԱաὝὕQq}
\tl_const:cn {c__str_case_3_X_0_tl} {ŊŋƮʈȒȓІіѪѫԲբḲḳẖ{ẖ}Ỻỻῂ{ὴι}ⲦⲧꚆꚇꝎꝏRr}
\tl_const:cn {c__str_case_3_X_1_tl} {ƯưΣσЇїԳգẗ{ẗ}Ὗὗῃ{ηι}Ss}
\tl_const:cn {c__str_case_3_X_2_tl} {ŌōȔȕΤτЈјѬѭӐӑԴդḴḵẘ{ẘ}Ỽỽῄ{ήι}ⲨⲩꚈꚉꝐꝑTt}
\tl_const:cn {c__str_case_3_X_3_tl} {ƱʊΥυЉљԵեẙ{ẙ}Uu}
\tl_const:cn {c__str_case_3_X_4_tl} {ŎŏƲʋȖȗΦφЊњѮѯӒӓԶզḶḷẚ{aʾ}Ỿỿῆ{ῆ}ⲪⲫꚊꚋꝒꝓVv}
\tl_const:cn {c__str_case_3_X_5_tl} {ƳƴΧχЋћԷէẛṡῇ{ῆι}Ww}
\tl_const:cn {c__str_case_3_X_6_tl} {ŐőȘșΨψЌќѰѱӔӕԸըḸḹῈὲⲬⲭꚌꚍꝔꝕXx}
\tl_const:cn {c__str_case_3_X_7_tl} {ƵƶͅιΩωЍѝԹթΈέYy}
\tl_const:cn {c__str_case_3_X_8_tl} {ŒœȚțΪϊЎўѲѳӖӗԺժḺḻẞ{ss}ῊὴⲮⲯꚎꚏꝖꝗZz}
\tl_const:cn {c__str_case_3_X_9_tl} {ƷʒΫϋЏџԻիΉή}
\tl_const:cn {c__str_case_4_X_0_tl} {ŔŕƸƹȜȝАаѴѵӘәԼլḼḽẠạὨὠῌ{ηι}ⲰⲱꚐꚑꝘꝙ}
\tl_const:cn {c__str_case_4_X_1_tl} {БбԽխὩὡ}
\tl_const:cn {c__str_case_4_X_2_tl} {ŖŗȞȟВвѶѷӚӛԾծḾḿẢảὪὢⲲⲳꚒꚓꝚꝛ}
\tl_const:cn {c__str_case_4_X_3_tl} {ГгԿկὫὣ}
\tl_const:cn {c__str_case_4_X_4_tl} {ŘřƼƽȠƞΰ{ΰ}ДдѸѹӜӝՀհṀṁẤấἈἀὬὤⅠⅰⲴⲵꚔꚕꝜꝝ}
\tl_const:cn {c__str_case_4_X_5_tl} {ЕеՁձἉἁὭὥⅡⅱ}
\tl_const:cn {c__str_case_4_X_6_tl} {ŚśȢȣЖжѺѻӞӟՂղṂṃẦầἊἂὮὦῒ{ῒ}ⅢⅲⲶⲷꚖꚗꝞꝟ}
\tl_const:cn {c__str_case_4_X_7_tl} {ЗзՃճἋἃὯὧΐ{ΐ}Ⅳⅳ}
\tl_const:cn {c__str_case_4_X_8_tl} {ŜŝȤȥИиѼѽӠӡՄմṄṅẨẩἌἄⅤⅴⲸⲹꝠꝡ}
\tl_const:cn {c__str_case_4_X_9_tl} {ЙйՅյἍἅⅥⅵ}
\tl_const:cn {c__str_case_5_X_0_tl} {ŞşȦȧКкѾѿӢӣՆնṆṇẪẫἎἆῖ{ῖ}ⅦⅶⲺⲻꝢꝣ}
\tl_const:cn {c__str_case_5_X_1_tl} {ЛлՇշἏἇῗ{ῗ}Ⅷⅷ}
\tl_const:cn {c__str_case_5_X_2_tl} {ŠšDŽdžȨȩМмҀҁӤӥՈոṈṉẬậῘῐⅨⅸⲼⲽꝤꝥ}
\tl_const:cn {c__str_case_5_X_3_tl} {DždžНнՉչῙῑⅩⅹ}
\tl_const:cn {c__str_case_5_X_4_tl} {ŢţȪȫОоӦӧՊպṊṋẮắῚὶⅪⅺⲾⲿꝦꝧ}
\tl_const:cn {c__str_case_5_X_5_tl} {LJljПпՋջΊίⅫⅻ}
\tl_const:cn {c__str_case_5_X_6_tl} {ĀāŤťLjljȬȭРрӨөՌռႠⴀṌṍẰằⅬⅼⳀⳁꝨꝩff{ff}}
\tl_const:cn {c__str_case_5_X_7_tl} {СсՍսႡⴁⅭⅽfi{fi}}
\tl_const:cn {c__str_case_5_X_8_tl} {ĂăŦŧNJnjȮȯТтӪӫՎվႢⴂṎṏẲẳⅮⅾⳂⳃꝪꝫfl{fl}}
\tl_const:cn {c__str_case_5_X_9_tl} {NjnjУуՏտႣⴃⅯⅿffi{ffi}}
\tl_const:cn {c__str_case_6_X_0_tl} {ĄąŨũȰȱФфӬӭՐրႤⴄṐṑẴẵἘἐⱠⱡⳄⳅꙀꙁꝬꝭffl{ffl}}
\tl_const:cn {c__str_case_6_X_1_tl} {ǍǎХхՑցႥⴅἙἑſt{st}}
\tl_const:cn {c__str_case_6_X_2_tl} {ĆćŪūȲȳςσЦцҊҋӮӯՒւႦⴆṒṓẶặἚἒῢ{ῢ}ⱢɫⳆⳇꙂꙃꝮꝯst{st}}
\tl_const:cn {c__str_case_6_X_3_tl} {ǏǐЧчՓփႧⴇἛἓΰ{ΰ}Ᵽᵽ}
\tl_const:cn {c__str_case_6_X_4_tl} {ĈĉŬŭШшҌҍӰӱՔքႨⴈṔṕẸẹἜἔᾀ{ἀι}ῤ{ῤ}ⰀⰰⱤɽⳈⳉꙄꙅ}
\tl_const:cn {c__str_case_6_X_5_tl} {AaǑǒЩщՕօႩⴉἝἕᾁ{ἁι}Ⰱⰱ}
\tl_const:cn {c__str_case_6_X_6_tl} {BbĊċŮůЪъҎҏӲӳՖֆႪⴊṖṗẺẻᾂ{ἂι}ῦ{ῦ}ⰂⰲⳊⳋꙆꙇ}
\tl_const:cn {c__str_case_6_X_7_tl} {CcǓǔЫыႫⴋᾃ{ἃι}ῧ{ῧ}ⰃⰳⱧⱨ}
\tl_const:cn {c__str_case_6_X_8_tl} {DdČčŰűЬьҐґӴӵႬⴌṘṙẼẽᾄ{ἄι}ῨῠⰄⰴⳌⳍꙈꙉ}
\tl_const:cn {c__str_case_6_X_9_tl} {EeǕǖЭэႭⴍᾅ{ἅι}ῩῡⰅⰵⱩⱪ}
\tl_const:cn {c__str_case_7_X_0_tl} {FfĎďŲųȺⱥЮюҒғӶӷႮⴎṚṛẾếᾆ{ἆι}ῪὺⰆⰶⳎⳏꙊꙋ}
\tl_const:cn {c__str_case_7_X_1_tl} {GgǗǘȻȼЯяႯⴏᾇ{ἇι}ΎύⰇⰷⱫⱬ}
\tl_const:cn {c__str_case_7_X_2_tl} {HhĐđŴŵҔҕӸӹႰⴐṜṝỀềᾈ{ἀι}ῬῥⰈⰸⳐⳑꙌꙍ}
\tl_const:cn {c__str_case_7_X_3_tl} {IiǙǚȽƚႱⴑᾉ{ἁι}ⰉⰹⱭɑꝹꝺ}
\tl_const:cn {c__str_case_7_X_4_tl} {JjĒēŶŷȾⱦҖҗӺӻႲⴒṞṟỂểᾊ{ἂι}ⰊⰺⱮɱⳒⳓꙎꙏ}
\tl_const:cn {c__str_case_7_X_5_tl} {KkǛǜϏϗႳⴓᾋ{ἃι}ⰋⰻⱯɐꝻꝼﬓ{մն}}
\tl_const:cn {c__str_case_7_X_6_tl} {LlĔĕŸÿϐβҘҙӼӽႴⴔṠṡỄễἨἠᾌ{ἄι}ⰌⰼⱰɒⳔⳕꙐꙑﬔ{մե}}
\tl_const:cn {c__str_case_7_X_7_tl} {MmŹźɁɂϑθႵⴕἩἡᾍ{ἅι}ⰍⰽꝽᵹﬕ{մի}}
\tl_const:cn {c__str_case_7_X_8_tl} {NnĖėǞǟҚқӾӿႶⴖṢṣỆệἪἢᾎ{ἆι}ῲ{ὼι}ⰎⰾⱲⱳⳖⳗꙒꙓꝾꝿﬖ{վն}}
\tl_const:cn {c__str_case_7_X_9_tl} {OoŻżɃƀႷⴗἫἣᾏ{ἇι}ῳ{ωι}ↃↄⰏⰿﬗ{մխ}}
\tl_const:cn {c__str_case_8_X_0_tl} {PpĘęǠǡɄʉͰͱҜҝԀԁႸⴘḀḁṤṥỈỉἬἤᾐ{ἠι}ῴ{ώι}ⰐⱀⳘⳙꙔꙕꞀꞁ}
\tl_const:cn {c__str_case_8_X_1_tl} {QqµμŽžɅʌϕφႹⴙἭἥᾑ{ἡι}ⰑⱁⱵⱶ}
\tl_const:cn {c__str_case_8_X_2_tl} {RrĚěǢǣɆɇͲͳϖπҞҟԂԃႺⴚḂḃṦṧỊịἮἦᾒ{ἢι}ῶ{ῶ}ⰒⱂⳚⳛꙖꙗꞂꞃ}
\tl_const:cn {c__str_case_8_X_3_tl} {SsſsႻⴛἯἧᾓ{ἣι}ῷ{ῶι}Ⱃⱃ}
\tl_const:cn {c__str_case_8_X_4_tl} {TtĜĝǤǥɈɉϘϙҠҡԄԅႼⴜḄḅṨṩỌọᾔ{ἤι}ῸὸⰔⱄⳜⳝꙘꙙꞄꞅ}
\tl_const:cn {c__str_case_8_X_5_tl} {UuƁɓႽⴝᾕ{ἥι}ΌόⰕⱅ}
\tl_const:cn {c__str_case_8_X_6_tl} {VvĞğƂƃǦǧɊɋͶͷϚϛҢңԆԇႾⴞḆḇṪṫỎỏᾖ{ἦι}ῺὼΩωⰖⱆⳞⳟꙚꙛꜢꜣꞆꞇ}
\tl_const:cn {c__str_case_8_X_7_tl} {WwႿⴟᾗ{ἧι}ΏώⰗⱇ}
\tl_const:cn {c__str_case_8_X_8_tl} {XxĠġƄƅǨǩɌɍϜϝҤҥԈԉჀⴠḈḉṬṭỐốᾘ{ἠι}ῼ{ωι}ⰘⱈⳠⳡꙜꙝꜤꜥ}
\tl_const:cn {c__str_case_8_X_9_tl} {YyჁⴡᾙ{ἡι}Ⱉⱉ}
\tl_const:cn {c__str_case_9_X_0_tl} {ZzĢģƆɔǪǫɎɏϞϟҦҧԊԋჂⴢḊḋṮṯỒồᾚ{ἢι}KkⰚⱊⱾȿⳢⳣꙞꙟꜦꜧ}
\tl_const:cn {c__str_case_9_X_1_tl} {ƇƈჃⴣᾛ{ἣι}ÅåⰛⱋⱿɀꞋꞌ}
\tl_const:cn {c__str_case_9_X_2_tl} {ÀàĤĥǬǭϠϡҨҩԌԍჄⴤḌḍṰṱỔổἸἰᾜ{ἤι}ⰜⱌⲀⲁꙠꙡꜨꜩ}
\tl_const:cn {c__str_case_9_X_3_tl} {ÁáƉɖჅⴥἹἱᾝ{ἥι}ⰝⱍꞍɥ}
\tl_const:cn {c__str_case_9_X_4_tl} {ÂâĦħƊɗǮǯϢϣҪҫԎԏḎḏṲṳỖỗἺἲᾞ{ἦι}ⰞⱎⲂⲃꙢꙣꜪꜫ}
\tl_const:cn {c__str_case_9_X_5_tl} {ÃãƋƌჇⴧἻἳᾟ{ἧι}Ⱏⱏ}
\tl_const:cn {c__str_case_9_X_6_tl} {ÄäĨĩǰ{ǰ}ϤϥҬҭԐԑḐḑṴṵỘộἼἴᾠ{ὠι}ⰠⱐⲄⲅꙤꙥꜬꜭꞐꞑ}
\tl_const:cn {c__str_case_9_X_7_tl} {ÅåDZdzἽἵᾡ{ὡι}Ⱑⱑ}
\tl_const:cn {c__str_case_9_X_8_tl} {ÆæĪīƎǝDzdzϦϧҮүԒԓḒḓṶṷỚớἾἶᾢ{ὢι}ℲⅎⒶⓐⰢⱒⲆⲇꙦꙧꜮꜯꞒꞓ}
\tl_const:cn {c__str_case_9_X_9_tl} {ÇçƏəἿἷᾣ{ὣι}ⒷⓑⰣⱓⳫⳬ}

The 'trick' here is to divide up the rather long list of chars into blocks, which means that the string comparison (relatively slow) doesn't have to map over the entire list (over 1000 chars) to find a match. As you'll see, it's only when there is a change available that there is any data to store at all.

The above should get added to expl3 'real soon now', depending on my time availability.


Since I was playing around with it 9 months after I asked the question, and developed a different approach, I will post it here. It achieves the result by making upper- or lower-cased characters active and then redefining them in the other lettercase.

It achieves the goal of the question, which was "I want to pass a macro the letter {S}, and have it execute the macro \csname macros\endcsname, or pass it the letter {T}, and have it execute the macro \csname macrot\endcsname."

However, it still has limitations, two big ones that come to mind:

  1. I can't operate operate on \def'ed information. Thus, I can say \macrofylc{T} and have it execute \csname macrot\endcsname, but I can't say \def\x{T}\macrofylc{\x}.

  2. It can handle macros in its arguments, but only if the macros are named in letters that are not being made active. Thus, I can \expresslc{This is An \textit{ITALIC} test} to get "this is an italic test", but I to make it upper case, I need the following kludge: \let\TEXTIT\textit\expressuc{This is An \TEXTIT{ITALIC} test} to get "THIS IS AN ITALIC TEST"

Note that limitation #2 is not a whole lot worse than the current state of affairs in LaTeX2e, since we are talking about things that are not regular expressions. However, I would dearly like to remedy limitation #1, but don't see how at this point.

Here is the MWE:

\documentclass{article}
\def\setuc{%
\8101\9`A=\8102\9\8101\9`B=\8102\9\8101\9`C=\8102\9\8101\9`D=\8102\9%
\8101\9`E=\8102\9\8101\9`F=\8102\9\8101\9`G=\8102\9\8101\9`H=\8102\9%
\8101\9`I=\8102\9\8101\9`J=\8102\9\8101\9`K=\8102\9\8101\9`L=\8102\9%
\8101\9`M=\8102\9\8101\9`N=\8102\9\8101\9`O=\8102\9\8101\9`P=\8102\9%
\8101\9`Q=\8102\9\8101\9`R=\8102\9\8101\9`S=\8102\9\8101\9`T=\8102\9%
\8101\9`U=\8102\9\8101\9`V=\8102\9\8101\9`W=\8102\9\8101\9`X=\8102\9%
\8101\9`Y=\8102\9\8101\9`Z=\8102\9%
}
\def\setlc{%
\8101\9`a=\8102\9\8101\9`b=\8102\9\8101\9`c=\8102\9\8101\9`d=\8102\9%
\8101\9`e=\8102\9\8101\9`f=\8102\9\8101\9`g=\8102\9\8101\9`h=\8102\9%
\8101\9`i=\8102\9\8101\9`j=\8102\9\8101\9`k=\8102\9\8101\9`l=\8102\9%
\8101\9`m=\8102\9\8101\9`n=\8102\9\8101\9`o=\8102\9\8101\9`p=\8102\9%
\8101\9`q=\8102\9\8101\9`r=\8102\9\8101\9`s=\8102\9\8101\9`t=\8102\9%
\8101\9`u=\8102\9\8101\9`v=\8102\9\8101\9`w=\8102\9\8101\9`x=\8102\9%
\8101\9`y=\8102\9\8101\9`z=\8102\9%
}
\def\resetuc{%
\8101\9`A=11\8101\9`B=11\8101\9`C=11\8101\9`D=11%
\8101\9`E=11\8101\9`F=11\8101\9`G=11\8101\9`H=11%
\8101\9`I=11\8101\9`J=11\8101\9`K=11\8101\9`L=11%
\8101\9`M=11\8101\9`N=11\8101\9`O=11\8101\9`P=11%
\8101\9`Q=11\8101\9`R=11\8101\9`S=11\8101\9`T=11%
\8101\9`U=11\8101\9`V=11\8101\9`W=11\8101\9`X=11%
\8101\9`Y=11\8101\9`Z=11%
}
\def\resetlc{%
\8101\9`a=11\8101\9`b=11\8101\9`c=11\8101\9`d=11%
\8101\9`e=11\8101\9`f=11\8101\9`g=11\8101\9`h=11%
\8101\9`i=11\8101\9`j=11\8101\9`k=11\8101\9`l=11%
\8101\9`m=11\8101\9`n=11\8101\9`o=11\8101\9`p=11%
\8101\9`q=11\8101\9`r=11\8101\9`s=11\8101\9`t=11%
\8101\9`u=11\8101\9`v=11\8101\9`w=11\8101\9`x=11%
\8101\9`y=11\8101\9`z=11%
}
\let\8\csname
\let\9\endcsname
\expandafter\let\csname101\endcsname\catcode
\expandafter\let\csname102\endcsname\active
\expandafter\let\csname103\endcsname\gdef
\expandafter\let\csname104\endcsname\resetuc
\expandafter\let\csname105\endcsname\resetlc
%%%%%%%%%%%%%%%%%%%%%%%%%
\def\macrofylc{\setuc\macrotransform}
\def\macrofyuc{\setlc\macrotransform}
\def\expresslc{\setuc\transform}
\def\expressuc{\setlc\transform}
\def\deflc{\setuc\deftransform}
\def\defuc{\setlc\deftransform}
%%%%%%%%%%%%%%%%%%%%%%%%%
\def\macrotransform#1{\csname macro#1\endcsname\resetuc\resetlc}
\def\transform#1{#1\resetuc\resetlc}
\def\deftransform#1{\def\thestring{#1}\resetuc\resetlc}
%%%%%%%%%%%%%%%%%%%%%%%%%
\setuc
% REDEFINE uc TO LOWERCASE
\8103\9A{a}\8103\9B{b}\8103\9C{c}\8103\9D{d}\8103\9E{e}\8103\9F{f}%
\8103\9G{g}\8103\9H{h}\8103\9I{i}\8103\9J{j}\8103\9K{k}\8103\9L{l}%
\8103\9M{m}\8103\9N{n}\8103\9O{o}\8103\9P{p}\8103\9Q{q}\8103\9R{r}%
\8103\9S{s}\8103\9T{t}\8103\9U{u}\8103\9V{v}\8103\9W{w}\8103\9X{x}%
\8103\9Y{y}\8103\9Z{z}%
\8104\9% \resetuc
%%%%%%%%%%%%%%%%%%%%%%%%%
\setlc
% REDEFINE LOWERCASE TO uc
\8103\9a{A}\8103\9b{B}\8103\9c{C}\8103\9d{D}\8103\9e{E}\8103\9f{F}%
\8103\9g{G}\8103\9h{H}\8103\9i{I}\8103\9j{J}\8103\9k{K}\8103\9l{L}%
\8103\9m{M}\8103\9n{N}\8103\9o{O}\8103\9p{P}\8103\9q{Q}\8103\9r{R}%
\8103\9s{S}\8103\9t{T}\8103\9u{U}\8103\9v{V}\8103\9w{W}\8103\9x{X}%
\8103\9y{Y}\8103\9z{Z}%
\8105\9% \resetlc
%%%%%%%%%%%%%%%%%%%%%%%%%
% THESE WILL TELL ME IF I HAVE SUCCEEDED OR NOT
\def\macrot{You have executed macrot}
\def\macroT{You have executed macroT}
\def\macrost{You have executed macrost}
\def\macroST{You have executed macroST}
\begin{document}
\textbf{Express directly: lc, then uc}\par
\expresslc{This IS a \textbf{Bold} \textit{Italic} test}\par
\let\TEXTBF\textbf\let\TEXTIT\textit% THIS IS A CHEAT
\expressuc{This IS a \TEXTBF{Bold} \TEXTIT{Italic} test that cheats.}\par

\textbf{Macrofy lc:}\par
\macrofylc{T}\par
\macrofylc{t}\par
\macrofylc{ST}\par
\macrofylc{St}\par
\macrofylc{sT}\par
\textbf{Macrofy uc:}\par
\macrofyuc{T}\par
\macrofyuc{t}\par
\macrofyuc{st}\par
\macrofyuc{sT}\par
\macrofyuc{St}\par

\textbf{Place in def:}\par
\deflc{This IS a \textbf{Bold} CASE}
Here is thestring stored by deflc: \thestring\par
\textit{UPPERCASE and lowercase are restored.}\par
\end{document}

enter image description here