17
\$\begingroup\$

(No, not this nor any of these)

Given a string and a list of strings, fill in the all blanks in the input string with corresponding strings.

Input/Output

The input string contains only alphabetic characters, spaces, and underscores. It is nonempty and does not start with an underscore. In other words, the input string matches the regex ^[a-z A-Z]([a-z A-Z_]*[a-z A-Z])?$

Every string in the input list is nonempty and contains only alphanumeric characters and spaces. In other words, they match the regex ^[a-z A-Z]+$.

A blank is a contiguous sequence of underscores (_) which is neither preceded nor proceeded by an underscore.

The input string contains n blanks for some positive integer n, and the list of strings contains exactly n strings.

The output is obtained by replacing each k-th blank in the input string by the k-th string in the input list of strings.

Example

Given an input string "I like _____ because _______ _____ing" and a list of strings ["ice cream", "it is", "satisfy"], we can find the output as follows:

  • The first blank comes directly after "like ". We fill that in with "ice cream" to get "I like ice cream because ______ _____ing".
  • The second blank comes directly after "because ". We fill that in with "it is" to get "I like ice cream because it is _____ing".
  • The third blank comes directly after "is ". We fill that in with "satisfy" to get "I like ice cream because it is satisfying".

We output the final string "I like ice cream because it is satisfying".

Test Cases

input string, input list => output
"Things _____ for those who ____ of how things work out _ Wooden",["work out best","make the best","John"] => "Things work out best for those who make the best of how things work out John Wooden"
"I like _____ because _______ _____ing",["ice cream","it is","satisfy"] => "I like ice cream because it is satisfying"
"If you are ___ willing to risk _____ you will ha_o settle for the ordi_____Jim ______n",["not","the usual","ve t","nary ","Roh"] => "If you are not willing to risk the usual you will have to settle for the ordinary Jim Rohn"
"S____ is walking from ____ to ____ with n_oss of ___ W_____ Churchill",["uccess","failure","failure","o l","enthusiasm","inston"] => "Success is walking from failure to failure with no loss of enthusiasm Winston Churchill"
"If_everyone_is_thinking ____ ____ somebody_isnt_thinking G____e P____n",[" "," "," ","alike","then"," "," ","eorg","atto"] => "If everyone is thinking alike then somebody isnt thinking George Patton"
"Pe_________e __say ____motivation does__ last Well___her doe_ bathing____thats why we rec____nd it daily _ __________lar",["opl","often ","that ","nt"," neit","s","  ","omme","Zig","Zig"] => "People often say that motivation doesnt last Well neither does bathing  thats why we recommend it daily Zig Ziglar"
\$\endgroup\$
0

30 Answers 30

5
\$\begingroup\$

Convex, 5 bytes

'_%.\

Try it online!

Convex is a CJam-based language, and this answer is almost the same as my CJam answer, except for l~ which is unneeded here, since Convex does automatic argument evaluation at the start of the program.

Explanation:

'_%.\ e# Full program only
'_    e# Push '_'
  %   e# Split and remove empty chunks
   .\ e# Vectorize by Swap
\$\endgroup\$
4
\$\begingroup\$

Japt, 8 bytes

r"_+"@Vv

Test it online!

I feel I missed some hidden catch in the rules because this is extremely simple: "replace each run of underscores in the string with the next item in the array."

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

JavaScript, 35 bytes

a=>b=>a.replace(/_+/g,a=>b.shift())

Try it online

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Same thing I had. Alternatively, a=>b=>String.raw({raw:a.split(/_+/)},...b) \$\endgroup\$ Commented Sep 21, 2017 at 3:03
2
\$\begingroup\$

Ruby, 28 + 1 = 29 bytes

$_=gsub(/_+/){|i|gets[/.*/]}

Uses -p

The first line is the format string, the rest of the lines are the array.

Try it online!

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

Proton, 42 bytes

a=>b=>re.sub("_+",_=>b.pop(0),a)
import re

Try it online!

Stupid imports...

Same thing in python:

Python 3, 53 bytes

lambda a,b:re.sub("_+",lambda _:b.pop(0),a)
import re

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ ...How did I frigging miss that. ._. \$\endgroup\$ Commented Sep 21, 2017 at 3:15
2
\$\begingroup\$

MATL, 9 bytes

'_+'i1&YX

Try it online!

Explanation

'_+'   % Push this string: regexp pattern
i      % Input cell array of replacement strings
1      % Push 1
&YX    % Four-input regexp replacement. This implicitly inputs the original
       % string, and consecutively replaces each first occurrence of the 
       % regexp pattern in that string by one of the replacement strings.
       % Implicitly display
\$\endgroup\$
2
\$\begingroup\$

CJam, 7 bytes

l~'_%.\

Try it online!

-1 thanks to a clever trick by Martin Ender.

Explanation:

l~'_%.\ e# Full program only
l       e# Input line
 ~      e# Eval
  '_    e# Push '_'
    %   e# Split and remove empty chunks
     .\ e# Vectorize by Swap
\$\endgroup\$
5
  • \$\begingroup\$ .\ instead of \]z. \$\endgroup\$ Commented Sep 21, 2017 at 12:20
  • \$\begingroup\$ @MartinEnder That works o_o \$\endgroup\$ Commented Sep 21, 2017 at 12:22
  • \$\begingroup\$ Sure, \ is a binary operator. :) \$\endgroup\$ Commented Sep 21, 2017 at 12:23
  • \$\begingroup\$ @MartinEnder Seems like I have gotten a bit too much in how mapping works in CJam then. \$\endgroup\$ Commented Sep 21, 2017 at 12:32
  • \$\begingroup\$ @MartinEnder OK on second thought how didn't I think of that? Not like I didn't know how mapping behaves e.g. [1 2 3]:_ -> [1 1 2 2 3 3] likewise for .... \$\endgroup\$ Commented Sep 21, 2017 at 16:22
2
\$\begingroup\$

Jelly, 8 7 bytes

ṣ”_¬Ðfż

Try it online! Edit: Saved 1 byte thanks to @Erik the Outgolfer. Explanation:

ṣ”_         Split on underscores
   ¬Ðf      Discard empty values
      ż     Zip with second input
            Implicit concatenated output
\$\endgroup\$
0
1
\$\begingroup\$

Perl 5, 25 + 1 (-p) = 26 bytes

@a=eval<>;s|_+|shift@a|eg

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Came up with basically the same, except using <> to negate the eval and shift: Try it online!. There's got to be a way to avoid the replacing the newlines... \$\endgroup\$ Commented Sep 21, 2017 at 7:35
  • \$\begingroup\$ This subroutine also has 26 bytes: sub{shift=~s|_+|shift|egr}. If you reversed the arguments, you could use pop and get it down to 22 bytes. \$\endgroup\$
    – nwellnhof
    Commented Sep 21, 2017 at 14:18
1
\$\begingroup\$

Python 2, 61 bytes

import re
s,l=input()
for i in l:s=re.sub('_+',i,s,1)
print s

Try it online!

Damn.

Python 2, 63 bytes

import re
f=lambda s,l:l and f(re.sub('_+',l[0],s,1),l[1:])or s

Try it online!

\$\endgroup\$
5
  • \$\begingroup\$ 60 bytes by passing re.sub a function \$\endgroup\$
    – Stephen
    Commented Sep 21, 2017 at 3:14
  • \$\begingroup\$ @Stephen Eh... That's just too close to your solution. I'll just stick to this and find more obscure solutions. :P \$\endgroup\$ Commented Sep 21, 2017 at 3:17
  • \$\begingroup\$ 53 bytes by using a function to improve @Stephen's proposal. \$\endgroup\$ Commented Sep 21, 2017 at 7:27
  • \$\begingroup\$ @JonathanFrech yeah, but that's exactly my answer already :P \$\endgroup\$
    – Stephen
    Commented Sep 21, 2017 at 15:27
  • \$\begingroup\$ @Stephen Oh; did not see your answer... :d \$\endgroup\$ Commented Sep 21, 2017 at 15:37
1
\$\begingroup\$

Pyth, 10 bytes

s.i:E"_+"3

Try it here!

How it works?

s.i:E"_+"3   Full program.

   :E    3   Split the second input on matches of the regex...
     "_+"    The regex "_+" (matches 1 or more underscores)
 .i          Interleave the elements of the split list with the input.
s            Join to a string.
\$\endgroup\$
1
\$\begingroup\$

RProgN 2, 11 bytes

x='_+'³[x‘r

Takes a string and a stack of strings on the top of the stack.

The first (top) element of a stack is to the right, hence input is right to left.

Explained

x='_+'³[x‘r
x=          # Set the stack of replacements to x
  '_+'³   r # Replace each chunk of _'s with the function...
       [    # Pop off the group of _'s
        x‘  # Pop the top element off x. Use that.

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Java 8, 57 bytes

a->s->{for(String i:a)s=s.replaceFirst("_+",i);return s;}

When I read the challenge I at first thought we should make a grammatically correct sentence with the words being in random order, but just replacing lines with each sequential word is easier. ;)

Explanation:

Try it here.

a->s->{            // Method with String-array and String parameter and String return-type
  for(String i:a)  //  Loop over the input-array
    s=s.replaceFirst("_+",i);
                   //   Replace the first line (1 or more adjacent "_") with the substring
                   //  End of loop (implicit / single-line body)
  return s;        //  Return the result
}                  // End of method
\$\endgroup\$
1
\$\begingroup\$

05AB1E, 12 bytes

„__¤:sv'_y.;

Try it online!

Explanation

„__¤:          # replace all runs of multiple "_" with a single "_"
     sv        # for each y in the list of replacements
       '_y.;   # replace the first instance of "_" with y
\$\endgroup\$
2
  • 1
    \$\begingroup\$ whoops fixed for +3 :p \$\endgroup\$ Commented Sep 21, 2017 at 12:14
  • \$\begingroup\$ @EriktheOutgolfer: Thanks for noticing. I rolled back to my previous version which handled that. \$\endgroup\$
    – Emigna
    Commented Sep 21, 2017 at 12:20
1
\$\begingroup\$

C# (.NET Core), 97 96 + 18 bytes

Saved 1 byte thanks to Kevin Cruijssen!

The 18 bytes are for using System.Linq.

s=>l=>string.Concat(s.Split('_').Where(x=>x!="").Zip(l.Concat(new[]{""}),(x,y)=>x+y).ToArray());

Try it online!

\$\endgroup\$
1
  • \$\begingroup\$ You can change (s,l)=> to s=>l=> to save a byte. Try it online! \$\endgroup\$ Commented Sep 21, 2017 at 12:53
1
\$\begingroup\$

Python 2, 49 bytes

s,l=input();import re;print re.sub("_+","%s",s)%l

Try it online!

The list input is taken as a tuple. Allowing actual lists as input would add another seven bytes, as a conversion would be required (tuple(...)).

\$\endgroup\$
1
\$\begingroup\$

Vyxal s, 6 bytes

\_/';Y

Try it Online!

Look Ma, no Unicode!

\_/    # Split on underscores
   ';  # Filter out empty strings
     Y # Interleave with fill-in values
       # (s flag) concatenate the top of stack
\$\endgroup\$
1
\$\begingroup\$

Factor, 34 bytes

[ R/ _+/ "%s"re-replace vsprintf ]

Try it online!

  • R/ _+/ "%s"re-replace Replace any amount of contiguous underscores with %s.
  • vsprintf Interpolate a sequence of strings into another string at every %s.
\$\endgroup\$
1
\$\begingroup\$

K (ngn/k), 27 bytes

{(*c),/y,'1_c:(~#:')_"_"\x}

Try it online!

Splitting based on "runs of underscores" seems longer than splitting by single underscores and removing empty strings.

{(*c),/y,'1_c:(~#:')_"_"\x}  x: string, y: substitution list
                     "_"\x    split by single underscores
              (~#:')_         remove empty strings
            c:                call it c
       y,'1_    zipped concatenate with c, head removed to match lengths
 (*c),/         join them and add back the head of c
\$\endgroup\$
2
  • \$\begingroup\$ you can also remove empty strings like this: ("_"\x)^,"" \$\endgroup\$
    – ngn
    Commented Aug 13, 2022 at 3:09
  • \$\begingroup\$ and save another 2 bytes: {,/(("_"\x)^,""),'y,,""} \$\endgroup\$
    – ngn
    Commented Aug 13, 2022 at 3:12
1
\$\begingroup\$

PowerShell Core, 46 bytes

param($a,$b)-join($a-split'_+'|%{$_
$b[$i++]})

Try it online!

\$\endgroup\$
1
\$\begingroup\$

Regex (RE2 or better), 23 bytes

s/_+(.*?)`([^`]*)/$2$1/

Try it online! - RE2
Try it online! - ECMAScript
Try it online! - Perl
Try it online! - PCRE2
Try it online! - Boost
Try it online! - Python
Try it online! - Ruby

This is a single regex substitution to be repeatedly applied until it has nothing to match (or until there is no change, where necessary or convenient). (See also the single-pass version.)

Input is taken as the string with blanks followed by the full list of string arguments, each delimited by `.

s/          # Begin substitution - match the following:
_+          # Match an entire blank
(.*?)`      # $1 = everything subsequent, up until but not including the first
            #      "`" delimiter; consume the delimiter
([^`]*)     # $2 = a string argument, captured up to but not including the next
            #      "`" delimiter; the ".*?" version would be "(.*?)(?=`|$)"
/           # Replace with the following:
$2$1        # "_+" is replaced with $2, and $1 is preserved, but the original
            # $2 is deleted.
/           # No flags - match and replace just once

sed -E, 31 bytes

:a
s/_+([^`]*)`([^`]*)/\2\1/
ta

Try it online!

sed lacks lazy quantifiers, so ([^,]*), must be used instead of (.*?), costing +2 bytes.

\$\endgroup\$
1
\$\begingroup\$

Regex (.NET), 46 bytes

s/_+(?<=((?=.*?(\2?`([^`]*)))_+.*?)*)|`.*/$3/g

Try it on regex101! - .NET

Input is taken as the string with blanks followed by the full list of string arguments, each delimited by `.

This is a single regex substitution, to be applied once. (See also the looped version.)

As such, for each individual match it must count how many blanks are to the left of the current one being replaced, because separate matches in a /global match or replace operation cannot communicate to each other (there is no persistent state between matches, other than the current position in the string). Variable-length lookbehind is used for this, with group-building to count string arguments in parallel with counting blanks. (I tried using balancing groups for the counting instead, and that took a bit more bytes.)

s/                       # Begin substitution - match the following:
    _+                       # Match an entire blank
    (?<=                     # Lookbehind – evaluated right-to-left, so read
                             # from the bottom up, until entering the lookahead,
                             # then read normally again.
        # When the below loop has finished, $3 will contain the string argument
        # of an index corresponding to the index of the blank matched above.
        (
            (?=              # Lookahead
                .*?          # Skip a minimal number of characters in order to
                             # match the following:
                (            # \2 = the following:
                    \2?      # Previous value of \2, if set
                    `        # Match a delimiter
                    ([^`]*)  # $3 = the next string argument (read up to but
                             #      not including the next delimiter, if any)
                )
            )
            _+               # Match an entire blank
            .*?              # Skip a minimal number of characters in order to
                             # match the above (since no backtracking will
                             # occur, they will all be non-underscores).
        )*                   # Iterate the above as many times as possible –
                             # for each blank matched (going right to left),
                             # \2 is appended with another string argument
                             # (going left to right).
    )
|                            # or...
    `.*                      # Match the entire list of string arguments,
                             # including first delimiter, to be deleted. This
                             # can only be matched after the first stage,
                             # above, has finished.
/                        # Replace with the following:
$3                           # The captured string argument
/                        # Flags:
g                            # Global – replace all matches in one sweep from
                             # left to right.

Regex (Pythonregex), 54 bytes

s/_+(?<=((?=.*?(?=(\3?))(\2`([^`]*)))_+.*?)*)|`.*/\4/g

Try it online! - Python import regex

A port of the .NET version. The captures \2 and \3 are copied back and forth to avoid use of nested backreferences, which Python doesn't support.

Regex (PCRE2 v10.35+), 96 bytes

s/_+(?*(.*`(.*)(.*$)))((?<=(?=^(?>.*?_+(?=[^`]*(\5?+`[^`]*)))+(?=\1)[^`]*\5\3$|(?4)).))|`.*/$2/g

Try it on regex101!
Attempt This Online!

This version emulates variable-length lookbehind using recursion with fixed-length lookbehind. But since capture groups cannot be returned from a subroutine call, the regex must make a guess as to what the subroutine call will return; this is done using (?*...) non-atomic lookahead. If the recursive call detects a mismatch between the guess and the actual result, it returns a non-match, forcing the non-atomic lookahead to try other guesses until one matches.

\$\endgroup\$
1
\$\begingroup\$

Raku, 24 bytes

->$_,\s{S:g[_+]=s.shift}

Try it online!

Replace and shift, like many answers.

\$\endgroup\$
1
\$\begingroup\$

brev, 36 28 bytes

Original attempt:

(fn(fold(fn(strse y"_+"x 1))x rest))

Wait, this works for 28:

(fn(strse x"_+"(pop! rest)))

Brev usually does poorly on here but since it was inspired by Snobol, I was happy to beat it.

\$\endgroup\$
0
\$\begingroup\$

Stacked, 21 bytes

[@y'_+'[y shift]repl]

Try it online!

Replaces all runs of _ with y shift. Nothing original, as it seems.

\$\endgroup\$
0
\$\begingroup\$

SOGL V0.12, 7 bytes

lΔ╔*№≤ŗ

Try it Here!

Explanation:

l        get the strings length
 Δ       range
  ╔*     multiply an underscore with each of the numbers
    №    reverse vertically (so the longest underscores get replaced first)
     ≤   put the array on top - order parameters for ŗ correctly
      ŗ  replace in the original string each any occurence of the underscores with its corresponding item in the array
\$\endgroup\$
0
\$\begingroup\$

Nim, 73 bytes

import pegs,sugar
proc f(s,b:auto):auto=s.replace peg"'_'*",(i,x,y)=>b[i]

Try it online!

\$\endgroup\$
0
\$\begingroup\$

Jelly (fork), 5 bytes

œṢ”_ż

Try it online! (or rather, don't, as this is a fork, not on TIO)

Full program, as we abuse Jelly's smash-printing.

How it works

œṢ”_ż - Main link. Takes a string S and a list of fillers F
œṢ    - Split S on runs of:
  ”_  -   Underscores
    ż - Zip with the fillers, and smash-print
\$\endgroup\$
0
\$\begingroup\$

Haskell, 61 bytes

s#(w:r)|(p,n)<-span(/='_')s=p++w++(snd$span(=='_')n)#r;s#[]=s

Try it online!

\$\endgroup\$
0
\$\begingroup\$

SNOBOL4 (CSNOBOL4), 51 bytes

	I =INPUT
R	I SPAN('_') =INPUT	:S(R)
	OUTPUT =I
END

Try it online!

\$\endgroup\$

Your Answer

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

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