0

The title of this question refers to words in a general sense but in my particular case I'm searching for numbers inside a previously defined macro. In that macro I have only numbers separated by spaces. I would like to search inside \teststr for a number stored in a counter, e.g.:

\newcounter{testx}
\newcounter{testy}
\def\teststr{ 1 2 3 4 5 9 10 11 30 }
\ExplSyntaxOn
\cs_generate_variant:Nn \seq_set_split:Nnn {NVV}
\cs_new:Npn \test #1#2#3{
 \int_set_eq:NN \l_tmpa_int {#2}
 \seq_set_split:NVV \l_tmpa_seq \l_tmpa_int {#1}
 \int_set:cn {c@#3} {(\seq_count:N \l_tmpa_seq) -1}}
\ExplSyntaxOff

The \test macro should be invoked the following way:

\test{\teststr}{\value{testx}}{testy}

In the following example, the counter testy stores the number 1. That's the expected behavior.

\setcounter{testx}{4}
\test{\teststr}{\value{testx}}{testy}

Now, testy should contains 0 as its value. Also it works:

\setcounter{testx}{6}
\test{\teststr}{\value{testx}}{testy}

But with 1 doesn't behaves as I would wish:

\setcounter{testx}{1}
\test{\teststr}{\value{testx}}{testy}

it stores 4 because \teststr contains four occurrences of 1, that's right but I would like to search like searching 'words', i.e. with spaces before and after the search pattern.

I did test with _tl and _str variable types on second arg of \seq_set_split without success.

Any help would be appreaciated. Thanks in advance.

2
  • you are not very clear what you want the code to do, it would likely be more efficient and simpler if you used a seq or clist rather than a space separated list, expl3 has functions provided out of the box to test if a value is a member of a seq Commented Mar 18, 2022 at 18:17
  • In simpler words, you want to count the occurrences of a specific number in your string? For instance, if the test string is 1 2 1 2 3 2 4, looking for 1 should return 2 and looking for 2 should return 3?
    – egreg
    Commented Mar 18, 2022 at 18:18

1 Answer 1

2

You can use \regex_count:nnN

\documentclass{article}

\newcounter{testx}
\newcounter{testy}
\def\teststr{ 1 2 3 4 5 9 10 11 30 }

\ExplSyntaxOn

\cs_generate_variant:Nn \regex_count:nnN { nV }
\cs_new_protected:Npn \test #1#2#3
 {
  \tl_set:Nx \l_tmpa_tl { \int_eval:n { #2 } }
  \regex_count:nVN { \b \u{l_tmpa_tl} \b } #1 \l_tmpa_int
  \int_set_eq:cN {c@#3} \l_tmpa_int
 }
\ExplSyntaxOff

\setcounter{testx}{4}
\test{\teststr}{\value{testx}}{testy}
\showthe\value{testy}

\setcounter{testx}{1}
\test{\teststr}{\value{testx}}{testy}
\showthe\value{testy}

\def\teststr{ 1 2 3 4 5 9 10 11 30 1}
\test{\teststr}{\value{testx}}{testy}
\showthe\value{testy}

\stop

In the console you get

> 1.
<recently read> \c@testy

l.20 \showthe\value{testy}

?
> 1.
<recently read> \c@testy

l.24 \showthe\value{testy}

?
> 2.
<recently read> \c@testy

l.28 \showthe\value{testy}
1
  • Thanks @egreg. It does the job.I forgot to mention that It would never happen that the string contains repeated numbers... so the first occurrence will be sufficient to store 1 on the counter provided via the third argument. Thank you! Commented Mar 18, 2022 at 21:00

You must log in to answer this question.

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