Let's say I have some string This~is a ~test
. I need to count the number of ~
characters. Is there some way to do this in LaTeX?
5 Answers
Using expl3
you can split the token list into items and then count the items (less 1):
2
4
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
% \CountSubStr{<substring>}{<string>}
\NewDocumentCommand{\CountSubStr}{ m m }{
\seq_set_split:Nnn \l_tmpa_seq { #1 } { #2 }
\int_eval:n {(\seq_count:N \l_tmpa_seq) - 1 }
}
\ExplSyntaxOff
\begin{document}
\CountSubStr{~}{This~is a ~test}% 2
\CountSubStr{yes}{a yes b yes c yes deyesfg yehs ij}% 4
\end{document}
For good measure, a LuaLaTeX-based solution:
\documentclass{article}
\usepackage{luacode} % for '\luastring' and '\luaexec' macros
\newcommand\tildecount[1]{\luaexec{
_ , count = string.gsub ( \luastring{#1} , "~" , "~" )
tex.sprint ( count ) }}
\begin{document}
\tildecount{This~is a ~test}
\tildecount{~~~~----&&&&****____####~~~~$$$$~~~~}
\end{document}
Addendum: The \tildecount
macro can easily be generalized to take a second input, viz., the string whose occurrences should be counted. The code for the generalized macro would be as follows:
\newcommand\StringCount[2]{\luaexec{
_ , count = string.gsub ( \luastring{#2} , \luastring{#1} , "" )
tex.sprint ( count ) }}
This macro may be used, for instance, as
\StringCount{yes}{a yes b yes c yes desyesfg mess ij}
(result: 4) or as
\StringCount{es}{a yes b mesh c best less xxDavieszz mess ij}
(result: 6).
A listofitems
approach.
\documentclass{article}
\usepackage{listofitems}
\newcommand\countem[2]{%
\setsepchar{#1}%
\readlist\countlist{#2}%
\the\numexpr\listlen\countlist[]-1\relax
}
\begin{document}
\countem{~}{This~is a ~test}
\countem{es}{a yes b mesh c best less xxDavieszz mess ij}
\end{document}
The MWE gives the appropriate answers of 2
and 6
.
You can use regular expressions:
\documentclass{article}
\usepackage{xparse}
\ExplSyntaxOn
\NewDocumentCommand{\countin}{smm}
{% #1 = * if searching in a macro
% #2 = string to search
% #3 = token list to search in
\IfBooleanTF { #1 }
{
\bruoga_countin:nV { #2 } #3
}
{
\bruoga_countin:nn { #2 } { #3 }
}
}
\cs_new_protected:Nn \bruoga_countin:nn
{
\regex_count:nnN { #1 } { #2 } \l_tmpa_int
\int_to_arabic:n { \l_tmpa_int }
}
\cs_generate_variant:Nn \bruoga_countin:nn { nV }
\ExplSyntaxOff
\begin{document}
\newcommand{\mytl}{This~is a ~test}
\countin{~}{This~is a ~test}
\countin*{~}{\mytl}
\countin{t}{This~is a ~test}
\countin{[Tt]}{This~is a ~test}
\countin{[aeiou]}{This~is a ~test}
\end{document}
This prints
2
2
2
3
4
The syntax for (simple) regular expressions is quite standard.
-
Using your solution, I have managed to count a character within an argument by assigning the argument to a macro
\def\labelvalue{#1}\def\coloncount{\countin*{:}{\labelvalue}}
. Printing the result works fine, but unfortunatelyMissing number, treated as zero. <to be read again> \xparse function is not expandable
is being thrown when comparing the result with an integer, e.g.\ifnum \coloncount=1
. I found this link mentioning your answer, but I didn't get their suggestion to work. Do you have any suggestions on how to make this work?– coreuterCommented Jul 26, 2023 at 15:44 -
@coreuter Please, ask a new question with the details as a followup to this one.– egregCommented Jul 26, 2023 at 15:45
-
thank you very much for your prompt reply! I have asked a new question: tex.stackexchange.com/q/692035/96582– coreuterCommented Jul 26, 2023 at 16:25
Consider substr.sty
.
Add \usepackage{substr}
and try
\CountSubStrings{~}{This~is a ~test} % -> 2
or
\newcounter{foo}
\SubStringsToCounter{foo}{;}{1;2;3;4}
\stepcounter{foo}
% \thefoo -> 4