6

For linguistic writing, I frequently deal with input data where sequences of capitals should be typeset not as capitals, but should be treated specially, e.g. be typeset in lower case, small caps. Ideally, I would like a package that provides a macro "morphemize" that scans through a string and applies a user-defined macro "morpheme" to any string of more than a single capital in there. This is the idea:

\morphemize{ pro.3PERS.FEM be.PAST-HABIT here}

should evaluate to:

pro.3\morpheme{PERS}.\morpheme{FEM} be.\morpheme{PAST}-\morpheme{HABIT} here

As far as I know there's nothing exactly like this out there, and I'll need to write a macro on my own. So, pointers to something similar would be appreciated.

3

Disclaimer: I'm not a linguist. From what I understand only multiple uppercase characters (A-Z) should be handled differently. Everything else (single upper case characters, a-z, punctuation, etc.) should be left untouched.

The user interface below consists of the \morphemize and \morpheme commands, as requested. Additionally, I have added the \xformupper command, which is applied to each uppercase character in a string of uppercase characters (this allows \lowercase to be used while maintaining expandability).

The basic process is to first split the argument of \morphemize at the spaces using \spacesplit@morphemize and pass the chunks to \@morphemize for uppercase sequence identification. This is required to preserve the spaces.

In \@morphemize, the command \is@upper is used to test for uppercase. If two are found in a row, then \@stringofuppers is used to get the uppercase string which is passed to \morpheme for processing. The \@stringoflowers strips the uppercase string and processes the remaining content with \@morphemize.

The solution (`' added to demonstrate that pre and post spaces are preserved):

\documentclass{article}%Answer for this question: http://tex.stackexchange.com/q/298719/89497
\makeatletter
    %document-level command to apply \morpheme to strings of uppercase characters (wrapper for \@morphemize)
    \newcommand{\morphemize}[1]{\spacesplit@morphemize#1 \nil\unskip}
    %document-level command applied to strings of uppercase characters
    \newcommand{\morpheme}[1]{\textsc{#1}}
    %document-level command applied to individual uppercase characters in strings up uppercase characters
    \newcommand{\xformupper}[1]{\lowercase{#1}}

    %Recursive command to split at spaces (otherwise they are lost)
    \def\spacesplit@morphemize#1 #2\nil{%
        \if\relax\detokenize{#1}\relax%preceeding space => eval the #2
            \space%
            \if\relax\detokenize{#2}\relax%#2 is empty=> do nothing
            \else
                \spacesplit@morphemize#2\nil%
            \fi
        \else%
            \@morphemize#1\nil%
            \if\relax\detokenize{#2}\relax%#2 is empty...do nothing
            \else
                \space\spacesplit@morphemize#2\nil%
            \fi
        \fi}

    %Recursive command to parse a string (without spaces) based on sequences of uppercase characters
    \def\@morphemize#1#2\nil{%
        \ifnum\is@upper#1\nil=1\relax%uppercase => treat differently
            \if\relax\detokenize{#2}\relax%#2 is empty => treat as a single captial (pass through)
                #1%
            \else%#2 is not empty => eval if next is capital
                \ifnum\is@upper#2\nil=1\relax%next char is uppercase => string of uppercases
                    \morpheme{\@stringofuppers#1#2\nil}%
                    \@stringoflowers#1#2\nil%
                \else%next char is not uppercase => pass through unchanged
                    #1\@morphemize#2\nil%
                \fi
            \fi
        \else%lowercase => pass through
            #1%
            \if\relax\detokenize{#2}\relax%#2 is empty => nothing left to parse
            \else%#2 is not empty => more to parse
                \@morphemize#2\nil%
            \fi
        \fi}

    %Command to return 1 if the first character is uppercase, 0 if other
    \def\is@upper#1#2\nil{%
        \ifx#1A 1\else
        \ifx#1B 1\else
        \ifx#1C 1\else
        \ifx#1D 1\else
        \ifx#1E 1\else
        \ifx#1F 1\else
        \ifx#1G 1\else
        \ifx#1H 1\else
        \ifx#1I 1\else
        \ifx#1J 1\else
        \ifx#1K 1\else
        \ifx#1L 1\else
        \ifx#1M 1\else
        \ifx#1N 1\else
        \ifx#1O 1\else
        \ifx#1P 1\else
        \ifx#1Q 1\else
        \ifx#1R 1\else
        \ifx#1S 1\else
        \ifx#1T 1\else
        \ifx#1U 1\else
        \ifx#1V 1\else
        \ifx#1W 1\else
        \ifx#1X 1\else
        \ifx#1Y 1\else
        \ifx#1Z 1\else
        0%
        \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
        \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi
        \fi\fi\fi\fi\fi\fi}

    %Recursive command expanding to the string of uppercase characters at the beginning of #1#2
    \def\@stringofuppers#1#2\nil{%
        \ifnum\is@upper#1\nil=1\relax%uppercase => carry on
            \if\relax\detokenize{#2}\relax%#2 is empty => add a nill
                \xformupper{#1}%
            \else%#2 not empty => evaluate next char
                \xformupper{#1}\@stringofuppers#2\nil%
            \fi
        \else\fi}%lowercase => do nothing

    %Recursive command expanding to the string of lowercase characters after a string of upper case characters at the beginning of #1#2
    %process the remaining contents with \@morphemize
    \def\@stringoflowers#1#2\nil{%
        \ifnum\is@upper#1\nil=1\relax%uppercase=>carry on
            \if\relax\detokenize{#2}\relax%#2 is empty => the whole content was all caps...return nothing
            \else%#2 not empty => evaluate next char
                \@stringoflowers#2\nil%
            \fi
        \else%lowercase =>process with \@morphemize
            \@morphemize#1#2\nil%
        \fi}
\makeatother
\begin{document}
\noindent\verb|\morphemize{ pro.3PERS.FEM be.PAST-HABIT here}|

`\morphemize{ pro.3PERS.FEM be.PAST-HABIT here}'

\noindent\verb|\morphemize{ singleCapiTaL.LETERS here}|

`\morphemize{ singleCapiTaL.LETERS here}'

\noindent\verb|\morphemize{with.A PO.ST-space }|

`\morphemize{with.A PO.ST-space }'
\end{document}

morphemize

I'm sure it could be tidied up a bit (expl3 would have been a better choice in hindsight). Also, it should be expandable, pending the user-defined \morpheme and \xformupper.

  • Wow, thanks a lot. That's exactly what I wanted -- only sequences of two or more capitals. – Uli S. Mar 15 '16 at 11:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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