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.

3
  • Removing \bfseries doesn't fix the problem, so I guess that the problem lies elsewhere.
    – Skillmon
    Commented Aug 13, 2017 at 12:27
  • Removing \bfseries and [temp] or removing \bfseries and changing [temp] to [\temp] works though.
    – Skillmon
    Commented Aug 13, 2017 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
    Commented Aug 13, 2017 at 12:51

3 Answers 3

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

5
  • I guess the OP wants \bfseries to have its usual effect
    – egreg
    Commented Aug 13, 2017 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
    Commented Aug 13, 2017 at 17:14
  • @egreg but reading onward I guess, I misinterpreted it.
    – Skillmon
    Commented Aug 13, 2017 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
    Commented Aug 15, 2017 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
    Commented Aug 15, 2017 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}
11
  • 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
    Commented Aug 13, 2017 at 14:06
  • The default is \let\temp=\empty. Commented Aug 13, 2017 at 14:18
  • Many thanks, Fischer. But the text "\bfseries" disappear in output of \temp. How to keep it?
    – lyl
    Commented Aug 13, 2017 at 14:30
  • @ John Kormylo, what's the meaning of "The default is \let\temp=\empty."?
    – lyl
    Commented Aug 13, 2017 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. Commented Aug 13, 2017 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}
3
  • 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
    Commented Aug 13, 2017 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
    Commented Aug 13, 2017 at 14:13
  • 1
    Maybe the OP can't use that LuaLaTeX code, but I can!
    – user139954
    Commented Feb 14, 2018 at 18:25

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .