Perl -p
, 22 bytes
/^(.*)\1+$(??{say$1})/
Try it online!
This uses a "postponed" regular subexpression embedded code block to accomplish the same thing as Raku's ex
haustive verb (which is used in Sean's answer), enumerating all possible matches, not just the ones (the one, in fact) that would be found normally.
Once a match of ^(.*)\1+$
that would be successful finishes, the embedded code block is triggered, and say$1
prints the value of the \1
capture group. Since it's of the "postponed" type, it then dynamically compiles the result of say$1
(which is the boolean 1
) into the regex, causing the match to fail, since 1
can never occur after the end of a string. A literal 1
placed after the $
would cause the match to fail and give up, due to Perl's regex optimization. But since it's dynamically compiled into the regex, the result of executing a piece of code, Perl doesn't know that it will be 1
every time, so it actually allows the regex to backtrack and try other possible matches.
The regex is intentionally set to not let \1
match the entire input string, only strict substrings. ^(.*)\1*$
would be the version that would also match the entire string. But that is left out, because once the program finishes, Perl's -p
flag causes $_
to be printed. That way, all of the string's divisors, including itself, are outputted.
Embedded code capability is a rare thing in regex engines. As far as I know, the only ones that have it are Perl and Raku (embedded code blocks) and PCRE (callouts). It appears that MATLAB allows execution of MATLAB code inside a regex, but I have not tested that yet (and am not sure if GNU Octave, which uses PCRE, has that functionality, or if MATLAB even also uses PCRE).
Another thing to note is that inputs followed by a newline (rather than EOF) will have that newline included in the contents of $_
, and this program doesn't use chomp
. But that doesn't matter, since $
matches both the true end of string, and the position immediately before a newline at the end of the string, if there is one. This is the case regardless of whether the m
ultiline flag is enabled (which it is not, by default). This is a case where that behavior (as opposed to \z
, which strictly matches the end of string) is helpful.
Perl -n
, 22 bytes
/^(.*)\1*$(??{say$1})/
Try it online!
This is really the more logical version, printing the divisors in a consistent order. But I'm keeping the -p
version up here, since -p
is much more commonly used in answers, and as the way flags are treated (as distinct languages, in a certain abstract way) it lets it be in the same playing field as those -p
answers. Not to mention that the workaround it uses is kind of fun.