17
\$\begingroup\$

This is not the same as m-ss-ng-lette-s

Challenge:

Given a string with masked characters, generate all possible words, inclusive of non-meaningfull words.

Rules:

  • The sequence of the characters in the string does not change.
  • The masked character (*) will be one of an English alphabets [a-z].
  • There are no line breaks, space, numbers, special characters or punctuations.
  • The output can be a list of non-meaningfull words too.
  • Any characters in a string can be masked. Not necessarily alternating characters.
  • For memory constraint, lets keep the maximum length of input as 10.

Example 1:

Input:

*o*

Output:

aoa
aob
aoc
...
...
...
boa
bob
boc
...
...
...
zoa
zob
zoc
...
...
...
zoz

Example 2:

Input:

*e*c*m*

Output:

aeacama
aeacamb
...
...
...
welcome
...
...
zezczmz

This is , so shortest answer in bytes wins!

\$\endgroup\$
5
  • 2
    \$\begingroup\$ Welcome to Code Golf and nice first question! For future reference, we recommend using the Sandbox to get feedback on challenge ideas before posting them to main. I've edited out the fastest-code tag as it's a winning criterion tag and this is code golf. \$\endgroup\$
    – emanresu A
    Jul 31, 2022 at 7:50
  • 1
    \$\begingroup\$ fastest-code and code-golf are both winning criterion tags. fastest-code means that the challenge is scored by the speed of solutions, by some metric; code-golf means that the shortest code wins. You can't have both. \$\endgroup\$
    – emanresu A
    Jul 31, 2022 at 8:08
  • 1
    \$\begingroup\$ Can delimiters between words be custom? E. g. use ` ` (space) instead of \n \$\endgroup\$
    – oeuf
    Jul 31, 2022 at 8:58
  • \$\begingroup\$ We can stick to *, as space may create ambiguity when combining with other solutions. \$\endgroup\$ Jul 31, 2022 at 9:07
  • 3
    \$\begingroup\$ I'd suggest allowing the masking character to be any non-alphabetical character. For most languages, the approach won't change, but the freedom of character is more likely to allow for the odd creative answer that only works for a specific masking character \$\endgroup\$ Jul 31, 2022 at 17:01

21 Answers 21

9
\$\begingroup\$

Haskell, 31 bytes

mapM q
q '*'=['a'..'z']
q c=[c]

Try it online!

\$\endgroup\$
8
\$\begingroup\$

Zsh, 25 bytes

eval echo ${1//\*/{a..z}}

Attempt This Online!

\$\endgroup\$
5
  • \$\begingroup\$ Why not use echo? \$\endgroup\$ Jul 31, 2022 at 8:35
  • \$\begingroup\$ @dingledooper echo won't print each of the word with a newline. \$\endgroup\$
    – oeuf
    Jul 31, 2022 at 8:59
  • \$\begingroup\$ 25 bytes if using custom delimiters (in this case a whitespace) is allowed. \$\endgroup\$
    – oeuf
    Jul 31, 2022 at 9:01
  • \$\begingroup\$ Nice solution, adding >> Result.log took care of large outputs. \$\endgroup\$ Jul 31, 2022 at 9:09
  • \$\begingroup\$ Very nice. Works in bash too with two escapes: eval echo ${1//\*/\{a..z\}} ATO \$\endgroup\$
    – Jonah
    Jul 31, 2022 at 19:00
8
\$\begingroup\$

Ruby, 39 bytes

->s{(?a..?z*10).grep /^#{s.tr'*',?.}$/}

Try it online!

The range is set to terminate after 10 zs, to fit the constraint. Realistically this takes forever to run unless a smaller number is used.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ You need to add ^...$ to the regex, otherwise words longer than the input will be included (See f['aa'] for an example) \$\endgroup\$
    – ovs
    Jul 31, 2022 at 11:32
  • \$\begingroup\$ @ovs fixed, thanks! \$\endgroup\$ Aug 1, 2022 at 0:29
7
\$\begingroup\$

Vyxal j, 5 bytes

×kaVΠ

Try it Online! Input as char lists.

   V  # Replace
×     # Asterisks
 ka   # With the lowercase alphabet
    Π # Take cartesian product
\$\endgroup\$
6
  • \$\begingroup\$ Get outgolfed lol \$\endgroup\$
    – naffetS
    Jul 31, 2022 at 18:44
  • 2
    \$\begingroup\$ @Steffan no, you get outgolfed lol \$\endgroup\$
    – emanresu A
    Aug 1, 2022 at 0:05
  • \$\begingroup\$ So the built-in for the string "*" is……… ×??? \$\endgroup\$
    – Fatalize
    Aug 1, 2022 at 11:35
  • \$\begingroup\$ @Fatalize Yep. I don't know why we have it, but it's occasionally useful. \$\endgroup\$
    – emanresu A
    Aug 1, 2022 at 11:50
  • \$\begingroup\$ @emanresuA But * is in the code page and is apparently multiplication… why not swap both symbols? \$\endgroup\$
    – Fatalize
    Aug 1, 2022 at 11:54
6
\$\begingroup\$

Perl 5 + -n -M5.10.0, 37 bytes

1 byte saved thanks to @Sisyphus!

$"=",";s/\*/{@{[a..z]}}/g;say<"$_\n">

Try it online!

Explanation

Turns the input into a glob (<"$_\n">) which is then evaluated as a list and printed (say) with newline separators.

Note: This does struggle to produce all the output for multiple *s when running on my phone!

\$\endgroup\$
4
  • 1
    \$\begingroup\$ save a byte using say<"$_\n"> instead of say for glob \$\endgroup\$
    – Sisyphus
    Jul 31, 2022 at 23:59
  • \$\begingroup\$ @Sisyphus Nice, I looked as using literal glob syntax, but not with a newline... Thank you! \$\endgroup\$ Aug 1, 2022 at 11:13
  • \$\begingroup\$ If you just read from stdin (which you do with -n), $_ will already have a newline, so you can ditch the \n. I guess in your "Try it online", there was no trailing newline in the input. (Add a newline, and you can ditch the \n) \$\endgroup\$
    – Abigail
    Aug 2, 2022 at 9:54
  • \$\begingroup\$ @Abigail I've definitely utilised this in other answers for both requiring and requiring no terminating newline. I've asked a question about what would be preferred. \$\endgroup\$ Aug 2, 2022 at 11:48
5
\$\begingroup\$

Python 3, 88 86 bytes

def A(x):p=x.find("*");~p and[A(x[:p]+chr(i+97)+x[p+1:])for i in range(26)]or print(x)

Removed 2 bytes thanks to @Adam

\$\endgroup\$
7
  • 1
    \$\begingroup\$ Welcome to Code Golf! \$\endgroup\$
    – naffetS
    Jul 31, 2022 at 18:40
  • \$\begingroup\$ You can remove A(input()) - simply defining a function is enough by our rules. \$\endgroup\$
    – naffetS
    Jul 31, 2022 at 18:40
  • \$\begingroup\$ Thanks! Should I add previous length to the title? \$\endgroup\$ Jul 31, 2022 at 18:52
  • \$\begingroup\$ You can if you want, but no need :) \$\endgroup\$
    – naffetS
    Jul 31, 2022 at 18:59
  • \$\begingroup\$ You can remove a byte by using ~x instead of x<0 and swapping around the conditions: def A(x):p=x.find("*");[A(x[:p]+chr(i+97)+x[p+1:])for i in range(26)]if~p else print(x). You can remove another by replacing if... else with and... or: def A(x):p=x.find("*");~p and[A(x[:p]+chr(i+97)+x[p+1:])for i in range(26)]or print(x) \$\endgroup\$ Jul 31, 2022 at 20:06
4
\$\begingroup\$

Vyxal j, 14 13 bytes

×Oka↔ƛ?×\%V$%

Try it Online!

Could be 8 bytes by using % instead of *

\$\endgroup\$
3
  • \$\begingroup\$ When trying for "welcome", getting debug console message as "Code timed out after 10 seconds" \$\endgroup\$ Jul 31, 2022 at 8:16
  • 3
    \$\begingroup\$ @GokulNathKP that's because the online interpreter is set to time out after 10 seconds. Either use a flag that increases the time out time or use the offline interpreter which doesn't have a time out limit \$\endgroup\$
    – lyxal
    Jul 31, 2022 at 8:22
  • 1
    \$\begingroup\$ Get outgolfed lol \$\endgroup\$
    – emanresu A
    Jul 31, 2022 at 8:52
4
\$\begingroup\$

Vyxal j, 9 bytes

×Ẇ⌈yvkaYΠ

Try it Online!

Based on emanresu A's answer, but shaves off another byte.

\$\endgroup\$
4
\$\begingroup\$

R, 65 bytes

f=\(s)`if`(grepl("[*]",s[1]),f(sapply(letters,sub,pa="[*]",s)),s)

Attempt This Online!

Basically the same recursive idea as in Cong Chen's answer.

\$\endgroup\$
4
\$\begingroup\$

Julia, 61 bytes

!s=join.(Iterators.product((x>'*' ? x : 'a':'z' for x=s)...))

Attempt This Online!

(This returns a matrix of all possible words, rather than a list/vector.)

\$\endgroup\$
1
  • \$\begingroup\$ Welcome to Code Golf! Although I do not know much Julia, I suspect that you can remove some whitespace in there. Otherwise, it is a great answer. \$\endgroup\$
    – Seggan
    Aug 4, 2022 at 4:18
3
\$\begingroup\$

Retina, 30 bytes

/\*/{%`$
25*$(¶$`
,Y0`*`l`\*.*

Try it online! Explanation:

/\*/{

Repeat while there are still any *s to process.

%`$
25*$(¶$`

Add 25 copies of each line.

,Y0`*`l`\*.*

Cyclically transliterate the first * on each line to the lowercase alphabet. The , tells Retina to process all matches and the 0 tells Retina to process the first character of each match.

\$\endgroup\$
3
\$\begingroup\$

lin, 49 bytes

"\*".?g.+_.+_"%s"?s.#t ?i len $a.~ `/\".t.~ sf"`'

Try it here! Returns an iterator of strings.

For testing purposes:

"*e*c*m*" ; \outln `' `_
"\*".?g.+_.+_"%s"?s.#t ?i len $a.~ `/\".t.~ sf"`'

Explanation

Prettified code:

"\*".?g.+_.+_ "%s"?s.#t ?i len $a.~ `/\ (.t.~ sf ) `'

Not very short, but surprisingly straightforward.

  • "\*".?g regex /\*/g
  • .+_.+_ "%s"?s.#t replace * with %s and store as t
  • ?i len get number of *s as n
  • $a.~ `/\ create length-n "digit" sequences from alphabet
  • (.t.~ sf ) `' use t to sprintf each sequence
\$\endgroup\$
3
\$\begingroup\$

sh + coreutils + hashcat, 31 bytes

sed s/*/?l/g|xargs hashcat -a 3
\$\endgroup\$
3
\$\begingroup\$

05AB1E, 9 bytes

'*A:.»â€S

Input as a list of characters.

Try it online or verify both test cases.

Explanation:

'*A:      '# Replace all "*" in the (implicit) input-list with the lowercase alphabet
    .»     # Left-reduce the list of strings by:
      â    #  Taking the cartesian product
       €S  # Then convert each inner list to a flattened list of characters
           # (after which the result is output implicitly)

Minor note: '* could be W in the legacy version of 05AB1E if the input is guaranteed to always contain a "*", but unfortunately the €S should be €˜J in that case, not saving any bytes.

\$\endgroup\$
3
\$\begingroup\$

Charcoal, 25 bytes

⊞υSFυ¿№ι*Fβ⊞υ⭆ι⎇⁻μ⌕ι*λκ⟦ι

Try it online! Link is to verbose version of code. Explanation:

⊞υS

Start with the input string.

Fυ

Check each string.

¿№ι*

If it contains a *, then:

Fβ

Loop over the lowercase alphabet.

⊞υ⭆ι⎇⁻μ⌕ι*λκ

Replace the first * in the string with the current letter and push it to the search list.

⟦ι

Otherwise output the string on its own line.

23 bytes using the newer version of Charcoal on ATO:

⊞υωFS≡ι*≔ΣEυEβ⁺κμυ≧⁺ιυυ

Attempt This Online! Link is to verbose version of code. Explanation:

⊞υω

Start with the empty string.

FS

Loop over the characters of the input string.

≡ι*

If the current character is a *, then...

≔ΣEυEβ⁺κμυ

... append each lowercase letter to each of the strings so far and join the resulting lists, otherwise...

≧⁺ιυ

... append the current character to each of the strings so far.

υ

Output the final list of strings.

\$\endgroup\$
2
\$\begingroup\$

R, 91 bytes

\(a,j=Vectorize(\(x,y)sub('*',y,x,,,T),'y'))`if`(grepl('*',a,,,T),sapply(j(a,letters),f),a)

Recursive solution.

Attempt This Online!

\$\endgroup\$
3
  • 1
    \$\begingroup\$ My solution uses basically the same recursive idea, so feel free to incorporate it into your answer: 65 bytes. \$\endgroup\$
    – pajonk
    Jul 31, 2022 at 19:05
  • \$\begingroup\$ Thanks! I think your solution is much better so recommend posting it. \$\endgroup\$
    – Cong Chen
    Jul 31, 2022 at 19:07
  • \$\begingroup\$ Thanks, posted. \$\endgroup\$
    – pajonk
    Jul 31, 2022 at 19:28
2
\$\begingroup\$

Factor + spelling, 60 56 bytes

[ 1 group { "*"} ${ ALPHABET } replace [ ] product-map ]

Attempt This Online!

                              ! "*o*"
1 group                       ! { "*" "o" "*" }
{ "*"} ${ ALPHABET } replace  ! { "abcdefghijklmnopqrstuvwxyz" "o" "abcdefghijklmnopqrstuvwxyz" }
[ ] product-map               ! { "aoa" "boa" ... "zoz" }
\$\endgroup\$
0
2
\$\begingroup\$

Brachylog, 13 bytes

ẹ{"*"∧!Ạ∋|}ᵐc

Try it online!

This is a generator predicate that will unify its output with each possible combination. The TIO example uses ᶠ - findall to generate all answers, but in a Prolog REPL you could just press ; repeatedly to get each answer.

Explanation

ẹ                Split the string into a list of characters
 {         }ᵐ    Map for each char:
  "*"              If the char is "*"
     ∧!              Cut (i.e. discard the "else" possibility)
        Ạ∋           The output is an element of the alphabet
          |        Else don’t modify the char
             c   Concatenate back to a string

The cut ! is necessary, otherwise the predicate would also generate answers with the asterisk unchanged.

\$\endgroup\$
2
\$\begingroup\$

JavaScript, 111 bytes

I feel like it's way too long and I'm missing something big.

s=>(r=s=>s[1]?.at?[...'abcdefghijklmnopqrstuvwxyz'].flatMap(c=>r(s.slice(1)).map(p=>s[0]+c+p)):s)(s.split('*'))
\$\endgroup\$
2
\$\begingroup\$

Also Python 3, 86 Bytes:

def f(x):
 for i in range(26):y=x.replace('*',chr(i+97),1);f(y)if'*'in y else print(y)
\$\endgroup\$
2
\$\begingroup\$

Julia, 61 bytes

!s=foldl((x,y)->[x.*y...],[x<'a' ? 'a'.+(0:25)' : x for x=s])

Attempt This Online!

\$\endgroup\$
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.