Regex (.NET), 23 bytes
(^x|(?>\2?)(\1)|x$|\b)*
Try it online!
Takes its input in unary, as a sequence of x
characters whose length represents the number. Returns its output as the capture count of group \1
.
This is based on Martin Ender's .NET regex for matching Fibonacci numbers. The .NET feature of balanced groups is used to count the number of iterations taken by the loop.
- That regex is first initially translated to use
x
as its unary numeral, yielding ^$|^(^x|(?>\2?)(\1))*x$
.
- Then the
x$
at the end is moved inside as the extra alternative |x$
, incrementing the loop count by \$1\$ for all \$n>0\$. This also allows us to remove the ^$|
at the beginning, because ^(^x|(?>\2?)(\1)|x$)*$
will now match \$n=0\$ on its own. (It will also now match numbers that are \$0\$ or \$1\$ less than a Fibonacci number, but we don't care because as specified by the challenge, all inputs will be Fibonacci numbers.)
- Then the extra alternative
|\b
is added to increment the loop count again for all \$n>0\$; \b
cannot match on an input of \$n=0\$ because there is no word character ([0-9A-Za-z_]
) to form a boundary with the absense of a word character, but it will always match at the end of a string of one or more x
s. The match is zero-width, so the loop will then be terminated.
- Then we remove the
^
and $
anchors sandwiching the regex, because we don't need to return a non-match for non-Fibonacci numbers.
27 byte version that matches iff the input is a Fibonacci number:
^(^x|(?>\2?)(\1)\B|x$|\b)*$
Try it online!
The \B
prevents numbers \$1\$ less than a Fibonacci number from being matched; in unary, \B
matches at every place except the beginning and end in a non-zero number (and matches "everywhere" in an input of zero).
Regex (.NET), 33 bytes
(?=(^(x)|(?>\3?)(\1)|)*)(?<-1>x)*
Try it online!
Returns its output as the sum of the lengths of the match (group \0
) and group \2
. It is done as a sum because for inputs \$n=1,2,3\$ the Fibonacci index is \$n+1\$ and would not fit in a single capture group.
Group \2
, which is (x)
in this regex, is captured as \$1\$ iff the loop takes at least one iteration, which happens for all \$n>0\$. The loop count itself is also given an extra increment, as in the 23 byte version above, by the addition of an empty alternative |
inside the loop. This will result in a zero-width match being taken at the end, regardless of input; it even happens for \$n=0\$, but that doesn't matter, because the (?<-1>x)*
will not have room to pop its capture, and the return match will be \$0\$ anyway.
Note that this regex would actually not be made shorter by returning its output as the sum of the lengths of \0
, \3
, and \3
, as the shortest way I can think of to do that takes 34 bytes:
(?=(^x|(?>\2?)(\1))*(x))?(?<-1>x)*
Try it online!
38 byte version that matches iff the input is a Fibonacci number:
^(?=(^(x)|(?>\3?)(\1)|)*x$|$)(?<-1>x)*
Try it online!
Regex (Perl / PCRE), 31 bytes
((?=(\2?x))(^x|\4?+(\3)))*(x|^)
Try it online! - Perl
Try it online! - PCRE
Returns its output as the sum of the lengths of groups \2
, \5
, and \5
. The regex saves 3 bytes just by using a possessive quantifier, replacing (?>\4?)
with \4?+
.
The Fibonacci index minus \$2\$ is built up in \2
using the expression (?=(\2?x))
. The first time this is hit, the \2?
will evaluate to zero because \2
isn't set yet, and \2
will be given a value of \$1\$. On every subsequent iteration, it will be incremented. This is done in a lookahead to avoid influencing the running total Fibonacci match, and is safe because at every step, the index will be less than the amount added to the full match.
The (x|^)
at the end serves to let \5
\$=1\$ in all cases except \$n=0\$.
This regex does not work under Java; group \2
just captures \$1\$ and stays there. This may be due to a bug in Java's regex engine.
33 byte version that matches iff the input is a Fibonacci number:
^((?=(\2?x))(^x|\4?+(\3)))*(x|^)$
Try it online! - Perl
Try it online! - PCRE
If the output specification must be simplified to sum only two groups, this would be the shortest way I can think of doing it (39 bytes, output is the sum of the lengths of groups \0
and \5
):
(?=((?=(\2?x))(^x|\4?+(\3)))*(x))?\2?x?
Try it online! - Perl
Try it online! - PCRE
42 byte version that matches iff the input is a Fibonacci number:
^(?=((?=(\2?x))(^x|\4?+(\3)))*(x|^)$)\2?x?
Try it online! - Perl
Try it online! - PCRE