Regex (Perl / PCRE), 21 bytes
^(<(((?1),)*(?1))?>)$
Uses the characters <>,
. (Avoids []
as they would require being \
-escaped.)
Try it online! - Perl
Try it on regex101 - PCRE1
Try it online! - PCRE2 v10.33
Attempt This Online! - PCRE2 v10.39+
Like the regex in the Raku answer, this uses recursion. Unlike Raku, standard regex has no concept of "separator" characters, so there's no concise way of implementing a comma-separated list, and the recursive call (?1)
needs to be in two places.
There are many alternatives of the same length:
Regex (Perl / PCRE), 21 bytes
^(<((?1)(,(?2))?)?>)$
Also uses the characters <>,
.
Try it online! - Perl
Try it online! - PCRE
Uses (?2)
recursion instead of *
repetition for the comma-separated list.
Regex (Perl / PCRE), 21 bytes
^(a((?1),)*(?1)?\Bz)$
Uses the characters az,
in order to take advantage of the \B
non-word-boundary assertion.
Try it online! - Perl
Try it online! - PCRE
Without the use of \B
, there would be nothing stopping a comma-separated list ending in a comma from being accepted, as the (?1)?
is optional independently of whether or not ((?1),)*
matched anything.
The \B
prevents this; if any list ended with a comma, the sequence ,z
would be part of it, so all we need to do is prohibit this sequence. \Bz
accomplishes this, as a
and z
are word-characters but ,
is not, thus there is no word boundary in the middle of az
or zz
but there is one in ,z
.
Regex (Perl / PCRE), 21 bytes
^(a\B(?1)?(,(?1))*z)$
Also uses the characters az,
. Mirror version of the above.
Try it online! - Perl
Try it online! - PCRE
Regex (Perl / PCRE), 21 bytes
^(<(\B(?1)|\b,\B)*z)$
Try it online! - Perl
Try it online! - PCRE
Uses the characters <z,
in order to take advantage of the \b
and \B
word- and non-word-boundary assertions.
Regex (Perl / PCRE), 21 bytes
^(a((?1)\B|\B,\b)*>)$
Uses the characters a>,
. Mirror version of the above.
Try it online! - Perl
Try it online! - PCRE
Regex (.NET), 35 33 29 bytes
^((a)+(?<-2>z)+(?(2),\b|$))+$
Uses the characters az,
in order to take advantage of the \b
word-boundary assertion.
Try it online!
Based on the old 35 byte one-liner in Neil's Retina answer.
-1 byte by using the characters <>,
instead of [],
, because [
needed to be \
-escaped
-1 byte by using an illegal character, instead of $.
, as the impossible condition to assert Group 2 being empty at the end
-4 bytes by using the characters az,
instead of <>,
, obviating the need for explicitly asserting Group 2 is empty at the end
^ # Assert that we're at the beginning of the string.
(
(a)+ # Capture at least one "a" on the Group 2 stack.
(?<-2>z)+ # Match at least one "z", popping an entry from the Group 2
# stack for each one we match.
(?(2),\b|$) # If the Group 2 stack is non-empty, match a "," followed by a
# word boundary (since "," is a non-word character, this means
# it must be followed by a word character, i.e. [0-9A-Za-z_]),
# else assert that we're at the end of the string.
)+ # Loop the above at least 1 time.
$ # Assert that we're at the end of the string. The Group 2
# conditional at the end of the above loop guarantees that the
# only way to end the loop at the end of the string is for
# Group 2 to be empty, due to the "\b" in its non-empty
# clause. So there's no need to explicitly assert here
# something like "(?(2)$.)" (which would assert something
# impossible in the case that Group 2 is non-empty).
Note that if the <>,
characters are still used, it can be 32 bytes:
^((<)+(?<-2>>)+(?(2),(?!$)|$))+$
Try it online!
\$\large\textit{Anonymous functions}\$
Perl, 33 bytes
sub{pop=~/^(<(((?1),)*(?1))?>)$/}
Try it online!
R, 49 48 44 39 bytes
\(L)grepl('^(<(((?1),)*(?1))?>)$',L,,1)
Attempt This Online!
-1 byte thanks to Giuseppe
-4 bytes by using grepl()
instead of sum(grep())
or any(grep())
-5 bytes by using a new anonymous function syntax introduced in R v4.1.0
$args-match'^((a)+(?<-2>z)+(?(2),\b|$))+$'
Try it online!
,[]
\$\endgroup\$[[]
\$\endgroup\$ListQ
... which doesn't quite meet these specs for non-lists. \$\endgroup\$