# Printing only the text that appears between two symbols

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
\startluacode
-- 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
context(str)
end
\stopluacode

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

\def\textmacro#1%
{\ctxlua{userdata.printBetweenMarks([===[#1]===])}}
% 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

-
I was thinking of adding a lpeg based solution, but your solution is cleaner. –  Aditya Mar 17 '12 at 23:25
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
\documentclass{article}
\makeatletter
\def\textmacro#1{\expandafter\@textmacro#1①②\@nil}
\def\@textmacro#1①#2②#3\@nil{%
\ifx\relax#2\relax#1\else#2\fi}
\makeatother
\begin{document}
\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.}
\end{document}


-
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