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.
\macrotand\macroT, so the case is not relevant. – egreg Apr 25 '14 at 17:16\active. Therefore I need to deal in macros with lowercase letters only in their names (note my use ofstringstringsin that answer). – Steven B. Segletes Apr 25 '14 at 17:37;-)However,\string Agives a category code 12Aindependently of the current category code ofA. – egreg Apr 25 '14 at 17:39