I have a macro which contains some text:

\textmacro{This is some text.}

Normally, when compiled, it should just print text, like this:

This is some text.

Sometimes, the text contains “①”and “②”, such as this:

\textmacro{①  This is some text. ② This is some other text.}

When that happens, I need it to only print the text appearing between “①”and “②”, like this:

This is some text.

How can I make the macro print the text between “①” and “②” in #1, if those symbols appear, otherwise, to just print all of the text?


You want a ConTeXt answer, right? Whenever I catch myself thinking "I know how to do this in an ordinary programming language", I shunt the text I want to operate on into LuaTeX. Taking the template from the wiki:

% First, the Lua function that will process the string
    -- remember, using the userdata namespace prevents conflicts
    userdata = userdata or {}

    function userdata.printBetweenMarks(str, m1, m2)
        -- default delimiters
        m1 = m1 or '①'
        m2 = m2 or '②'

        match_pattern = string.format('%s(.*)%s', m1, m2)
        str = string.match(str, match_pattern) or str

% Secondly, the ConTeXt command that passes the string to the Lua function.

    % Note that Lua sees the text as-is, so we have to wrap it in string
    % delimiters ourselves.
    % [=*[ is Lua's double-bracket string delimiter style; this way, the
    % code only fails if the text contains ']===]'.

EDIT: removed a print() statement I had used for debugging

  • 1
    I was thinking of adding a lpeg based solution, but your solution is cleaner.
    – Aditya
    Mar 17 '12 at 23:25
  • 1
    Thanks! Add your solution anyway, perhaps, if you feel like it? There's More Than One Way To Do It, after all; and lpeg scales in complexity better than string.match; and reading your answer will help me improve my woeful lpeg knowledge/understanding. ;-)
    – Esteis
    Mar 17 '12 at 23:39
  • Can userdata.printBetweenMarks([===[#1]===])} be placed within another \startlua and \stoplua? I tried placing it there, but just get errors.
    – Village
    Apr 3 '12 at 5:36
  • @Village: that gives errors because you can't use #1 when you're not defining a TeX macro. (In my example, \ctxlua was part of a macro definition.) Things that will work: userdata.printBetweenMarks([=[① mystring ②]=]) (more on strings in Lua; and userdata.printBetweenMarks(str), where str is a variable containing the string you want to work on. Read this tutorial on LuaTeX for more info.
    – Esteis
    Apr 4 '12 at 15:09
  • Three snippets that may help you: (1) \ctxlua{str = "mystring"} (or 'mystring', [[mystring]], [=[mystring]=], etc.); (2) \def\savestring#1{\ctxlua{str = "#1"}} followed by \savestring{asdf}; and (3) \def\passStringToFunction{\ctxlua{myfunction("#1")}}.
    – Esteis
    Apr 4 '12 at 15:15
\textmacro{This is some text.}\par
\textmacro{①  This is some text. ② This is some other text.}\par
\textmacro{This is some text ①  This is some other text. ② This is some text.}

enter image description here

  • 1
    Notice that if one uses this with pdflatex and \usepackage[utf8]{inputenc}, the second example fails because of the \expandafter. +1 anyway. :)
    – egreg
    Mar 17 '12 at 11:21

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.