# Challenge

Given a positive-length string $$\S\$$, a divisor of $$\S\$$ is another (not necessarily distinct) string for which there exists a number $$\a\$$ such that when we repeat the divisor $$\a\$$ times, we get the string $$\S\$$.

For example, the string abcd is a divisor of the string abcdabcd with $$\a=2\$$.

Your challenge is, given a positive-length string $$\S\$$, output all of $$\S\$$'s divisors.

For example, the string aaaa has three divisors: a, aa, and aaaa.

# Input/Output

Input/output can be taken in any reasonable format for taking a string and returning the set of divisors of that string.

The input string will only has lowercase characters, and it contains no whitespace or special characters.

The output list should not contains any duplicates. The strings can appear in any order.

Testcase:

Input -> Output
abcdabcd -> abcd, abcdabcd
aaa -> a, aaa
aaaaaaaa -> a, aa, aaaa, aaaaaaaa
abcdef -> abcdef

This is , so shortest answer (in bytes) wins!

• If $s\times a=S$, why only $s$ is considered divisor but not $a$. :)
– tsh
Commented Aug 11, 2022 at 5:37

# Brachylog, 3 bytes

ġ=h

Try it online!

Generator.

ġ      Split the input into (roughly) equal slices.
h    Output one of them
=     if they're all equal.
• What's this roughly equal stuff mean? Commented Aug 12, 2022 at 0:06
• Commented Aug 12, 2022 at 0:10

# Python, 53 bytes

lambda s,t="":[t for c in s if~-any(s.split(t:=t+c))]

Attempt This Online!

• This is Python 3.8+ I presume? Due to the walrus operator? Commented Aug 11, 2022 at 16:36
• @justhalf Yes, well observed. Commented Aug 11, 2022 at 16:52
• Ah, I see. So we no longer distinguish Python 2 and 3+ here, or .. ? Commented Aug 11, 2022 at 20:17
• @justhalf Python is Python 3, Python 2 is officially no longer supported. Besides, all the boiler plate elements of this post are auto-generated by ato. So if you don't like it take it out with them. I'm sure they'll be very interested to hear from you. Commented Aug 11, 2022 at 20:35
• Oh, I'm just so used to TIO boilerplate that does distinguish them. Nothing against ATO :) Also I thought Python 3.7 and Python 3.8 are considered different too in codegolf. Is it not the case now? Commented Aug 12, 2022 at 4:21

# Regex (ECMAScript 2018 or better), 17 bytes

(?<=(.*))(?=\1*$) Try it online! - ECMAScript 2018 Try it online! - Python (import regex) Try it online! - .NET Try it on regex101! - ECMAScript 2018 or .NET Returns its output as the list of matches' \1 captures. Ports: Try it online! - Java, 18 bytes: (?<=(^.*))(?=\1*$)
Try it online! - Perl, 31 bytes: (?=(.*)).((?<=(?=^\1*$|(?2)).)) Try it online! - PCRE2, 31 bytes - same as above Try it on regex101! - PCRE2 Try it online! - PCRE, 33 bytes: (?=(.*)).((?<=(?=‍¶|^\1*$|(?2)).))
Try it on regex101! - PCRE1

# 05AB1E, 6 5 bytes

ηʒKõQ

Explanation:

η      # Get all prefixes of the (implicit) input-string
ʒ     # Filter it by:
K    #  Remove all occurrences of the prefix-string from the (implicit) input
õQ  #  Check if what remains is an empty string
# (after which the filtered list is output implicitly as result)

# Factor + grouping.extras, 737057 48 bytes

[ dup head-clump [ ""replace ""= ] with filter ]

Attempt This Online!

-13 bytes and then -9 more by porting @KevinCruijssen's 05AB1E answer (and then improved version)!

• Factor has such crazy builtins, you'd think it's got to have one to get set partitions Commented Aug 11, 2022 at 3:12
• @Steffan Sadly, it does not. I would say that is possibly my biggest annoyance about golfing in Factor. Commented Aug 11, 2022 at 3:20

# Curry (PAKCS), 26 bytes

f(g a)=a
g a|a>""=a++g a?a

Try it online!

# Haskell, 42 bytes

f s|p<-scanr(:)""s=[t|t<-p,a<-p,(a*>t)==s]

Try it online!

scanr(:)""s lists the suffixes of the input s. For each suffix t, we look for a suffix a where repeating t once for each character of a (a*>t) gives the original string s.

# J, 19 bytes

<\#~<=<$~&.>#+#\|# Try it online! • <$~ Cyclically extend each prefix to the following length:
• #+#\|# Length of input # + the remainder when we divide that prefix's length into the input's length #\|#. This ensures non-divisible prefixes won't match.
• <= Which of the extended prefixes matches the input?
• <\#~ Filter all prefixes using that mask.

Try it

for c (${(s..)1})s+=$c&&[[ $1 = ($s)# ]]&&<<<$s Try it online! Fairly straightforward: for c (${(s..)1})       # (s)split $1 on '' (into characters) s+=$c &&            # append character to $s [[$1 = ($s)# ]] && # if$1 equals $s repeated <<<$s              # output $s # 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 exhaustive 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 multiline 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.