14
\$\begingroup\$

Because rickrolling is the greatest meme on Earth, you [know the rules and so do I] are to write the shortest code that can textually rickroll the unsuspecting reader. Let [you down] there be an input text which contains letters, punctuation, and spaces. Anytime a [lie and hurt you] phrase from the first two stanzas appears in the text...

We're no strangers to love
You know the rules and so do I
A full commitment's what I'm thinking of
You wouldn't get this from any other guy
I just wanna tell you how I'm feeling
Gotta make you understand

Never gonna give you up
Never gonna let you down
Never gonna run around and desert you
Never gonna make you cry
Never gonna say goodbye
Never gonna tell a lie and hurt you

...insert the rest of the line in brackets afterwards.

Input

Input is a single line string containing only printable ASCII with optional trailing newline.

Output

Output is a single-line string. Any time that a group of words (defined as the input string split on spaces) matches a group of words in lines of the lyrics above, insert the remaining words of the line into the string, grouped in square brackets.

Additional Description:

This is code-golf, fewest bytes wins. You may write a program or function.

  • matching should be case insensitive: we're is converted to we're [no strangers to love] even though We're is capitalized in the lyrics.
  • matching should be greedy. Does he know the answer? should be converted to Does he know the [rules and so do I] answer? instead of Does he know [the rules and so do I] the [rules and so do I] answer?
  • If a word appears more than once in the provided lyrics, choose any of the occurrences to complete the line.
  • If a word is the last word in the lyric line, don't insert anything after it.
  • Punctuation is included as part of a "word." I'm is a single word and cannot match with I. Similarly, you. doesn't match with any lyrics because of the period.

Some words like I appear multiple times throughout the lyrics as well as at the end of a line. Since the rule is that any occurrence in the above lyrics can be used, and one of those occurrences is at the end of a line, no matching of I is necessary. The other option for I is [just wanna tell you how I'm feeling].

If two matches overlap, you may choose either one. This means that how I'm thinking could become how I'm [feeling] thinking [of] OR how [I'm feeling] I'm thinking [of] since the I'm could be part of either how I'm or I'm thinking. If, however the input text was simply I'm thinking, then the output should be I'm thinking [of].

Additional test cases:

I don't know what I'm doing with my life.
is converted to
I [just wanna tell you how I'm feeling] don't know [the rules and so do I] what I'm [thinking of] doing with my life.
Many additional solutions are possible, since words like `I` appear multiple times.


Will someone please save me from these memes?
is converted to
Will someone please save me from [any other guy] these memes?


Two strangers walked into a bar.  One said "hello."  The other said "goodbye."
is converted to
Two strangers [to love] walked into a [lie and hurt you] bar.  One said "hello."  The [rules and so do I] other [guy] said "goodbye."

Challenge inspired by this dude.

\$\endgroup\$
2
  • 13
    \$\begingroup\$ ಠ_ಠ​​​​​​​​​​​​ \$\endgroup\$
    – Alex A.
    Jan 9, 2016 at 20:28
  • 1
    \$\begingroup\$ Second test case appears to be wrong (from should become from [any other guy]). \$\endgroup\$
    – Doorknob
    Jan 9, 2016 at 22:00

1 Answer 1

7
\$\begingroup\$

gawk, 316+377 = 693

First command line parameter is the lyrics' filename (375 bytes + 2 for invocation = 377). Rickrolls all other files. Prints to stdout.

BEGIN{FPAT="[^ ]+ *";OFS=""}func d(a){b=tolower(a);sub(/ *$/,"",b);return b}FNR==NR{for(s=$0;NF;$0=s=$0){for(i=1;i<NF;i++){k=k $i;$i="";v[d(k)]="["$0"] "}$0=s;k=$1=""}next}{for(s=$0;NF;$0=s=$0){for(j=NF;(--j)>0&&!(d($0) in v);$(j+1)="");k=v[d($0)];if($0!~/ $/)k=" "k;printf($0 k);for($0=s;j-->=0;$(j+2)="");}print""}

Ungolfed

BEGIN{FPAT="[^ ]+ *";OFS=""}
func d(a){b=tolower(a);sub(/ *$/,"",b);return b}
FNR==NR{
  for(s=$0;NF;$0=s=$0){
    for(i=1;i<NF;i++)
    {
      k=k $i;
      $i="";
      v[d(k)]="["$0"] "
    }
    $0=s;
    k=$1=""
  }
  next
}
{
  for(s=$0;NF;$0=s=$0){
    for(j=NF;(--j)>0&&!(d($0) in v);$(j+1)="");
    k=v[d($0)];
    if($0!~/ $/)k=" "k;
    printf($0 k);
    for($0=s;j-->=0;$(j+2)="");
  }
  print""
}

Test results

Input:

we're
We're
Does he know the answer?
I
how I'm thinking
I'm thinking
I don't know what I'm doing with my life.
Will someone please save me from these memes?
Two strangers walked into a bar.  One said "hello."  The other said "goodbye."
gonna run

Output:

we're [no strangers to love] 
We're [no strangers to love] 
Does he know the [rules and so do I] answer? 
I [just wanna tell you how I'm feeling] 
how I'm [feeling] thinking [of] 
I'm thinking [of] 
I [just wanna tell you how I'm feeling] don't know [the rules and so do I] what I'm [thinking of] doing with my life. 
Will someone please save me from [any other guy] these memes? 
Two strangers [to love] walked into a [lie and hurt you] bar.  One said "hello."  The [rules and so do I] other [guy] said "goodbye." 
gonna run [around and desert you] 
\$\endgroup\$
5
  • \$\begingroup\$ 1. This fails the first test case (it puts things between what and I'm, which is "non-greedy" matching). 2. This fails the third test case (it turns the two spaces into one). 3. If you store the lyrics in a separate file, you need to count that file (as well as +2 for including it in the awk command) in your byte count. \$\endgroup\$
    – Doorknob
    Jan 9, 2016 at 21:41
  • \$\begingroup\$ @Doorknob Thanks. The greed is fixed. The lyrics file does not add to my character count since it is unaltered and was publicly available before the challenge started. I don't count awk's source code either. \$\endgroup\$
    – Rainer P.
    Jan 9, 2016 at 23:36
  • \$\begingroup\$ Now this fails for the input gonna run (expected output gonna run [around and desert you], actual output gonna [tell a lie and hurt you] run [around and desert you]). It also still chomps multiple spaces in a row. You need to count the lyrics file in your byte count, as it's a non-standard invocation of the awk program. \$\endgroup\$
    – Doorknob
    Jan 9, 2016 at 23:39
  • \$\begingroup\$ @Doorknob Ok. I reimplemented most of the program and require gawk now for space-preserving field separation. Passes all test cases now. \$\endgroup\$
    – Rainer P.
    Jan 10, 2016 at 15:11
  • \$\begingroup\$ Impressive. It was very difficult to cover all the edge cases in this challenge. \$\endgroup\$
    – Doorknob
    Jan 10, 2016 at 16:54

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.