g | x | w | all
Bytes Lang Time Link
280Python3250518T024750ZAjax1234
123JavaScript Node.js231020T191521Zl4m2
019Jelly231020T200418ZJonathan
077R231021T135401ZNick Ken
074JavaScript ES6231020T190405ZArnauld
nanJ231020T205915ZJonah
032Charcoal231020T214309ZNeil
041Retina 0.8.2231020T205349ZNeil
095Ruby231020T185726ZValue In

Python3, 280 bytes

def f(c,w):
 a,*U,b=c.split()
 if w in a or w in b:return
 for i in range(1,len(w)):
  if(K:=''.join(U))==w[i:len(K)+i]:
   W=w[i+len(K):]
   if a[:-i]and b[len(W):]and a[-i:]==w[:i]and b[:len(W)]==W:return 1
  W=a+''.join(U)+b
  if W[:i]==w[:i]and W[-(len(w)-i):]==w[i:]:return 1

Try it online!

JavaScript (Node.js), 123 bytes

x=>y=>(z=x.split` `.join``,g=i=>z[i]==y[i]?g(i+1):y[i]&&i*z.endsWith(y.slice(i))||eval(`/.${y}./`).test(z))(0)&&!x.match(y)

Try it online!

-1B from noodle man

Jelly, 19 bytes

Uses some of Unrelated String's answer to Is it a circumfix? saving bytes over using the "outfix quick", ÐƤ.

ḲFŒṖḢ;ṪƊ€;ṖḊẆƊƲḟẆ{i

A dyadic Link that accepts the clue on the left and the answer on the right and yields a positive integer (truthy) if valid or zero (falsey) otherwise.

Try it online! (Some tests have been shortened in the middle since the algorithm is inefficient.)

How?

ḲFŒṖḢ;ṪƊ€;ṖḊẆƊƲḟẆ{i - Link: Clue, Answer
Ḳ                   - split {Clue} on space characters
 F                  - flatten -> Squished
              Ʋ     - last four links as a monad - f(Squished):
  ŒṖ                -   all partitions (no empty parts)
       Ɗ€           -   for each: last three links as a monad - f(Partition):
    Ḣ               -     head (remove first part and yield it)
      Ṫ             -     tail (remove last part of that and yield it ...
                                                ...or integer zero* if nothing left)
     ;              -     concatenate
                         -> Bookends (plus an invalid one with a trailing zero*)
             Ɗ      -   last three links as a monad - f(Squished):
          Ṗ         -     pop (remove the tail character)
           Ḋ        -     dequeue (remove the head character)
            Ẇ       -     all sublists
                         -> Hiddens
         ;          -   {Bookends} concatenate {Hiddens} -> Potential Answers
                Ẇ{  - sublists of {Clue}
               ḟ    - {Potential Answers} filter discard {Clue sublists}
                       -> Valid Answers (plus an invalid bookend with a trailing zero*)
                  i - 1-indexed index of {Answer} in* {Valid Answers} ...
                                                 ...or zero if not found
                      
                       * Integer zero wont match a zero character

R, 77 bytes

\(x,y,`/`=grepl)"^((.+)(.+)) (\\2.*\\3$|.+\\1.)"/paste(y,gsub(" ","",x))&!y/x

Attempt This Online!

A function taking two character arguments and returning a logical value. Inspired by @Neil’s Retina answer so be sure to upvote that one too! The regular expression here is slightly different because of R’s requirement to escape backslashes.

JavaScript (ES6), 74 bytes

A significantly shorter version suggested by Nick Kennedy and using Neil's regular expression.

Expects (clue)(word). Returns a Boolean value.

c=>w=>c.match(w)</^(.+)(.+),(\1.*\2$|.+\1\2.)/.test([w,c.split` `.join``])

Try it online!


JavaScript (ES6), 86 bytes

Expects (clue)(word). Returns a Boolean value.

The "bookend" test is based on the method used by Deadcode in this answer.

c=>w=>c.match(w)</^(.+)(.+),\1.*\2$/.test([w,s=c.split` `.join``])+!!s.match(`.${w}.`)

Try it online!

Commented

c =>                // outer function taking c = clue
w =>                // inner function taking w = hidden word
c.match(w)          // look for w in c; the comparison will succeed 
<                   // if this is null and the right side is > 0
/^(.+)(.+),\1.*\2$/ // regular expression for the "bookend" test
.test([             // applied to this array coerced to a string:
  w,                //   the word, followed by a comma
  s = c.split` `    //   followed by s,
       .join``      //   which is c without spaces
]) +                // end of test()
!!s.match(`.${w}.`) // for word breaks, we look for w in s with at
                    // least one char. before and one char. after

J, 52 51 45 bytes

-.@rxin*[e.((]#~#@[>:#\@](-.|."{[),&#)-.&' ')

Attempt This Online!

This approach allows us to avoid treating the two cases of bookends and word breaks as separate:

J, 52 bytes

-.@rxin*[((rxin g)+.[e.-~&#(g=.}:@}.)@(]\.)])' '-.~]

Attempt This Online!

Another nice candidate for J's outfix adverb. Reading through other answers I was reminded that this approach is similar to my answer on Is it a cirumfix as well.

Charcoal, 32 bytes

‹№θη∨№⁻θ η⊙η∧κ¬∨⌕⁻θ …ηκ⌕⮌⁻θ ⮌✂ηκ

Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for a valid clue, nothing if not. Explanation:

 №                                  Count of
   η                                Input word in
  θ                                 Input clue
‹                                   Is less than
     №                              Count of
         η                          Input word in
       θ                            Input clue
      ⁻                             With spaces removed
    ∨                               Logical Or
           η                        Input clue
          ⊙                         Any index satisfies
             κ                      Current index
            ∧                       Logical And
                  θ                 Input clue
                 ⁻                  With spaces removed
                ⌕                   Does not start with
                     η              Input word
                    …               Truncated to length
                      κ             Current index
               ∨                    Logical Or
                          θ         Input clue
                         ⁻          With spaces removed
                        ⮌           Reversed
                       ⌕            Does not start with
                              η     Input word
                             ✂      Sliced from
                               κ    Current index
                            ⮌       Reversed
              ¬                     Logical Not

Retina 0.8.2, 41 bytes

 |^(.+)¶.*\1

^(.+)(.+)¶(\1.*\2$|.+\1\2.)

Try it online! Takes input as the word and clue on separate lines but link is to test suite that splits on comma and exchanges the word and clue. Explanation:

 |^(.+)¶.*\1

Delete spaces in the clue, but delete the word if is is a contiguous substring of the clue, which prevents the following match from succeeding.

^(.+)(.+)¶(\1.*\2$|.+\1\2.)

Check that the word either bookends or is now contained in the clue.

Ruby, 95 bytes

Bookends code is a slight tweak of my old answer to Is it a circumfix?

->s,w{t=s.tr' ','';(t=~/.#{w}./||(1...~-z=w.size).any?{w==t[0,_1]+t[_1-z..]}&&z<t.size)&&!s[w]}

Attempt This Online!