Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I want to change the letter-case of a single character argument, and use that changed letter inside a \csname. And I want to do it without an additional package.

For example, 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.

In my MWE, I show three approaches:

  1. I didn't expect \lowercase to work, since I recall reading that it is not truly expanded until the last possible moment. Surprisingly, it goes into an \edef okay, but it must not be truly expanded, because it breaks the \csname.

  2. I also formulated an approach where I used \numexpr to add 32 to the ASCII code of the argument and perform a \char upon that result. Like \lowercase, it gives the appearance of being expandable, but it also fails inside the \csname.

  3. I finally achieve success with the stringstrings package. Having written the package, I know the conversion was not pretty... essentially, it is an exhaustive 26-fold check of the form \if #1Aa\else\if #1Bb\else\if #1Cc\else...\fi\fi\fi, which has the virtue that it can be expandably placed into an \edef, and so it works.

There has to be a better way. The MWE works only because I use the inefficiently calculated \tmp from METHOD 3 inside the \csname. If I use \tmp from either of the two earlier methods, it breaks.

\documentclass{article}
\usepackage{stringstrings}
\def\macros{Expandably converted an S to a s}
\def\macrot{Expandably converted a T to a t}
\newcommand\convert[1]{%
  %MAKE THE ARGUMENT LOWER CASE
  1) LOWERCASE\\
  \edef\tmp{\lowercase{#1}}% PRETENDS TO EXPAND, BUT FAILS IN \csname
  Here is the ``expanded'' conversion: \tmp\\
  % OR
  2) ASCII CONVERSION\\
  \edef\tmp{\expandafter\char\numexpr`#1+32\relax}% PRETENDS TO EXPAND, BUT FAILS IN \csname
  Here is the ``expanded'' conversion: \tmp\\
  % OR
  3) STRINGSTRINGS PACKAGE\\
  \caselower[q]{#1}\def\tmp{\thestring}% WORKS BUT USES A PACKAGE
  Here is the ``expanded'' conversion: \tmp\\
  %
  Now use it in a csname: \csname macro\tmp\endcsname%
}
\begin{document}
\convert{S}\par
\convert{T}
\end{document}

enter image description here


SUMMARY OF ANSWERS:

I have added egreg's code snippets into this MWE to produce a document (and not just terminal output), showing the methods put forth to this point:

\documentclass{article}

%%%%%%%%%%%%%%%%%%%%%%%%%%%% L3 APPROACH

\usepackage{expl3}

\ExplSyntaxOn
\cs_set_eq:NN \Xexplower \tl_expandable_lowercase:n
\ExplSyntaxOff

%%%%%%%%%%%%%%%%%%%%%%%%%%%% EGREG'S LESS HACKY SOLUTION

\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
}

%%%%%%%%%%%%%%%%%%%%%%%%%%%% STEVE'S HACKY PACKAGE APPROACH

\usepackage{stringstrings}

%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\def\macros{Expandably converted an S to a s}
\def\macrot{Expandably converted a T to a t}

\begin{document}

\textbf{Steve's hacky approach}

\caselower[q]{S}\csname macro\thestring\endcsname\par
\caselower[q]{T}\csname macro\thestring\endcsname

\textbf{egreg's less hacky approach}

\edef\lcstring{\explowerchar{S}}\csname macro\lcstring\endcsname\par
\edef\lcstring{\explower{T}}\csname macro\lcstring\endcsname

\textbf{L3 approach}

\edef\lcstring{\Xexplower{S}}\csname macro\lcstring\endcsname\par
\edef\lcstring{\Xexplower{T}}\csname macro\lcstring\endcsname

\end{document}

enter image description here

share|improve this question
    
My feeling for the original problem, however, is that you should simply define \macrot and \macroT, so the case is not relevant. –  egreg Apr 25 at 17:16
    
@egreg For a question such as this, one boils the problem to the essence. The real problem at hand references this answer of mine, tex.stackexchange.com/questions/173209/…, in which capital letters are \active. Therefore I need to deal in macros with lowercase letters only in their names (note my use of stringstrings in that answer). –  Steven B. Segletes Apr 25 at 17:37
1  
Well, you have discovered why it's better not to activate letters. ;-) However, \string A gives a category code 12 A independently of the current category code of A. –  egreg Apr 25 at 17:39

2 Answers 2

up vote 7 down vote accepted

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 \tl_expandable_lowercase:n
\ExplSyntaxOff

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

Terminal output:

> \lcstring=macro:
->astring with spac\'es?.
share|improve this answer
    
No, if you use Knuth TeX. But I tested it with pdftex, pdflatex, lualatex and xelatex. Compile from the terminal or use \meaning instead of \show. –  egreg Apr 25 at 15:46
    
Fascinating. I'm not used to operating in a "terminal condition." –  Steven B. Segletes Apr 25 at 15:50
    
@StevenB.Segletes \show uses the same code as error messages, so it can't be used in an interactive session. I added an easier version. ;-) –  egreg Apr 25 at 15:53
    
The first works fine in Knuth TeX with the help of package intcalc: \input intcalc.sty\relax or \usepackage{intcalc} and the following \ifcase line: \ifcase\intcalcSub{\number`#1}{65} % –  Heiko Oberdiek Apr 25 at 15:58
    
Indeed, we are currently planning to add 'case folding' to expl3 with a more 'sensible' name (currently \str_fold_case:n): full 'lowercasing' is more-or-less impossible expandably due to requirements of Unicode specs. –  Joseph Wright Apr 25 at 16:00

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 '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.

share|improve this answer
    
Note: probably there is some work to do on category codes: everything should come out as 'other' chars. –  Joseph Wright Apr 25 at 16:14
    
I didn't realize I was opening a can of worms :^) –  Steven B. Segletes Apr 25 at 16:16
1  
@StevenB.Segletes The team have been working on this very area recently: case changing is a current weakness in expl3 as we've only really provided the primitives renamed. The Unicode people have worked very hard on the entire area, and it's now a question of implementing what they say. Case folding is the easiest part as there is no language/context-sensitivity. –  Joseph Wright Apr 25 at 16:22
    
BTW, if you are really interested I'll 'convert' the expl3 to 'normal' TeX, but it's a bit of a pain here as it needs not only the 'code itself' but also the \str_case_x:nnF stuff, so will get a bit long! –  Joseph Wright Apr 25 at 16:29
    
To paraphrase Otto von Bismarck, "LaTeX3 coding is like sausages, it is better not to see them being made." –  Steven B. Segletes Apr 25 at 16:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.