1

I want to handle a string of characters to get my desired string by the package xstring, here is my code:

    \documentclass[12pt,a4paper]{article}
    \usepackage{xstring}

    \begin{document}

    \StrBefore{aaa \bfseries bbb;some other text}{;}[\temp]
\temp

    \end{document}

The output string I want is "aaa \bfseries bbb",but the code fails to compile. I think the reason is the existence of "\bfseries", the character "\" causes the failure. Anyone can help me with this problem? Thank you.

  • Removing \bfseries doesn't fix the problem, so I guess that the problem lies elsewhere. – Skillmon Aug 13 '17 at 12:27
  • Removing \bfseries and [temp] or removing \bfseries and changing [temp] to [\temp] works though. – Skillmon Aug 13 '17 at 12:32
  • Sorry, I forgot a "\" in [temp]. I just corrected it. And, I don't want to remove "\bfseries", the oupput string I want should contain it,that is to say "aaa \bfseries bbb". – lyl Aug 13 '17 at 12:51
1

I hope I understand what you want (printing \bfseries as a result and not interpreting it). This can be done by changing it to a string with \string or \detokenize. Note that in the default font the backslash is printed as high ticks if you use this option.

\documentclass[12pt,a4paper]{article}
\usepackage{xstring}

\begin{document}

\StrBefore{aaa \detokenize{\bfseries} bbb;some other text}{;}[\temp]
\temp\\
\StrBefore{\detokenize{aaa \bfseries bbb;some other text}}{;}[\temp] % works, too
\texttt{\temp}% with \texttt the backslash is printed

\end{document}

enter image description here

  • I guess the OP wants \bfseries to have its usual effect – egreg Aug 13 '17 at 16:57
  • @egreg "Many thanks, Fischer. But the text "\bfseries" disappear in output of \temp. How to keep it? " is what he wrote as comments under Ulrike Fischer's answer. Based on this, I thought he doesn't and because of this, I wrote this answer. – Skillmon Aug 13 '17 at 17:14
  • @egreg but reading onward I guess, I misinterpreted it. – Skillmon Aug 13 '17 at 17:17
  • @Skillmon by the marco \detokenize, I get the wanted string format. Then in later call (yes, in later call after the string has been handled), how to make \bfseries excute ? – lyl Aug 15 '17 at 1:35
  • @lyl how much string handling do you need? The \bfseries is also persistent in Ulrike's answer. The \detokenize macro does what it's called, it detokenizes its argument. I don't know any way how to revert that later on. If it's just the splitting of the string you need, go with Ulrike's answer. You should maybe give us the complete use case, so we can provide working answers for your problem. – Skillmon Aug 15 '17 at 8:41
4

You need to prevent the expansion of \bfseries:

\documentclass[12pt,a4paper]{article}
 \usepackage{xstring}

 \begin{document}
 \noexpandarg  
 \StrBefore{aaa  \bfseries bbb;some other text}{;}[\temp]
 \temp

 \end{document}
  • Might it be a good idea to provide a fall-back instruction in case the pattern (here: ;) doesn't occur in the search string? – Mico Aug 13 '17 at 14:06
  • The default is \let\temp=\empty. – John Kormylo Aug 13 '17 at 14:18
  • Many thanks, Fischer. But the text "\bfseries" disappear in output of \temp. How to keep it? – lyl Aug 13 '17 at 14:30
  • @ John Kormylo, what's the meaning of "The default is \let\temp=\empty."? – lyl Aug 13 '17 at 14:31
  • What do you mean by \bfseries disappears? It is a command and is executed when you call \temp, that's why the bbb is bold. – Ulrike Fischer Aug 13 '17 at 14:33
1

Here's a LuaLaTeX-based solution. (Lua has a very powerful string manipulation library.) The answer sets up a LaTeX macro called \StringBefore, which calls a Lua function that does the actual work. The macro \StringBefore is expandable; it can be made the argument of some other macro, as is done in the code below. Incidentally, I'm assuming that if the character(s) in the second argument aren't found in the search string, nothing should be returned.

enter image description here

% !TeX program = lualatex
\documentclass{article}
\usepackage{luacode} % for "\luastringN" macro and "luacode" env.
\begin{luacode} 
function string_before ( str, patt ) 
  n = string.find ( str, patt ) 
  if n then -- string.find made (at least) one match...
      tex.sprint ( string.sub ( str, 1, n-1) )
  else   -- no match -> print nothing
      tex.sprint ( "" ) 
  end
end
\end{luacode}
\newcommand\StringBefore[2]{\directlua{ 
    string_before(\luastringN{#1},\luastringN{#2})}}
\begin{document}

\StringBefore{aaa {\bfseries bbb} ccc;some other text}{;}

\newcommand{\temp}{\StringBefore{ddd {\bfseries eee} \emph{ggg} hhh;dummy text}{;}}

\temp

\StringBefore{aaa {\bfseries bbb} ccc;some other text}{u} % no match

zzz
\end{document}
  • Many thanks, Mico. Because I know nothing about lua, this code is too complex for me to understand. Is there any other way to handle my question? – lyl Aug 13 '17 at 14:08
  • @lyl - Did you take a look at Ulrike's answer? You haven't provided any information as to what you're trying to achieve with the sub-string extraction business. Depending on your use case, it may be more straightforward to teach yourself the basics of Lua than it is to proceed with the tools of the xstring package. Lua has a very powerful string library (basically, a direct adaptation of the string library of C). – Mico Aug 13 '17 at 14:13
  • 1
    Maybe the OP can't use that LuaLaTeX code, but I can! – user139954 Feb 14 '18 at 18:25

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.