16
\$\begingroup\$

Introduction:

Inspired by the Puzzling-stackexchange post with the same name, which I've answered four years ago:

Can you create a perfectly valid English sentence, which makes perfect sense, but which contains the word "and" in it, five times consecutively in a row ?

"Something-or-other and and and and and something-else."

With my answer:

Let's say we have a store owner and his clerk. The store owner want the clerk to make a sign for the shop, which has the name (for example): "Toys And Puzzles".
So, the clerk makes the sign and presents it to the owner.

The owner thinks the spacing isn't really good. It currently looks something like:
Toys And Puzzles
but he wanted it to look more like:
Toys And Puzzles

So he says to the clerk:
"The spacing between Toys and And and And and Puzzles should be a bit larger. Could you please fix that?"

Challenge:

Given a string input, replace all occurrences of the word 'and' with five times that word; three in lowercase, interleaved with two of the original cased word.

Some examples:

  • AND would become and AND and AND and
  • and would become and and and and and
  • AnD would become and AnD and AnD and

There is one catch however ():

You're not allowed to use the characters aAnNdD in your source code. Any other character is still allowed, even if it's the unicode value of these letters, only these six characters themselves are banned.

Challenge rules:

  • Your source code cannot contain any of the characters aAnNdD.
  • You can assume the input-string only contains spaces and letters (both lower- and uppercase)
  • You can assume the input is non-empty
  • It is possible that the input-string does not contain the word 'and', in which case it's returned as is
  • Instead of a string you are also allowed to take the input as a list/array/stream of characters/code-point-integer (or other similar variations)
  • Don't replace substrings of and if it isn't a standalone word (see test cases with stand, band, and Anderson)

General rules:

  • This is , so shortest answer in bytes wins.
    Don't let code-golf languages discourage you from posting answers with non-codegolfing languages. Try to come up with an as short as possible answer for 'any' programming language.
  • Standard rules apply for your answer with default I/O rules, so you are allowed to use STDIN/STDOUT, functions/method with the proper parameters and return-type, full programs. Your call.
  • Default Loopholes are forbidden.
  • If possible, please add a link with a test for your code (i.e. TIO).
  • Also, adding an explanation for your answer is highly recommended.

Test cases:

Input:  "Toys And Puzzles"
Output: "Toys and And and And and Puzzles"

Input:  "and"
Output: "and and and and and"

Input:  "AND and anD"
Output: "and AND and AND and and and and and and and anD and anD and"

Input:  "Please stand over there and watch" # note that the "and" in "stand" isn't changed
Output: "Please stand over there and and and and and watch"

Input:  "The crowd loves this band" # note that the "and" in "band" isn't changed
Output: "The crowd loves this band"

Input:  "Toys and And and And and Puzzles"
Output: "Toys and and and and and and And and And and and and and and and and And and And and and and and and and Puzzles"

Input:  "Mr Anderson went for a walk and found a five dollar bill" # note that the "And" in "Anderson" isn't changed
Output: "Mr Anderson went for a walk and and and and and found a five dollar bill"
\$\endgroup\$
  • 11
    \$\begingroup\$ It's too bad that the ban on andAND letters in code means a lot of language constructs just aren't allowed, making a regex-based method even more tempting. And Python can't print, return, or lambda, and so needs some imagination to even output anything. \$\endgroup\$ – xnor Jul 23 at 10:33
  • 1
    \$\begingroup\$ @xnor Good point. I just felt that without the restriction I'd only see the basic replace (?i)\band\b with and $0 and $0 and for language with regex, and felt it needed something enforcing people to be a bit more creative with their answers, hence the restricted-source. I also realize this is just a flaw in my base challenge, since do-X-without-Y challenges are usually discouraged, but I felt without it the challenge would be too boring. Out of curiosity: what would you have changed to still have the base challenge, but without only seeing the to-the-point regex-replace approach? \$\endgroup\$ – Kevin Cruijssen Jul 23 at 12:07
  • 1
    \$\begingroup\$ @Shaggy Due to the amount of answers already I'd say no, sorry. It indeed doesn't add much to split on spaces at the start and join by spaces at the end. But considering the answers that would need some changes, and since I mentioned only letters and spaces are valid input-characters, I think it's best to leave it as is now. But if you have convincing arguments otherwise, lmk please. \$\endgroup\$ – Kevin Cruijssen Jul 23 at 15:26
  • 3
    \$\begingroup\$ @KevinCruijssen I don't have any good ideas for dealing with regex being too good. Honestly, I often avoid writing string-manipulation challenges because of this. \$\endgroup\$ – xnor Jul 23 at 21:56
  • 3
    \$\begingroup\$ @AdHocGarfHunter Heh, I didn't mean to hype it as interesting, was just saying the obvious things aren't allowed. \$\endgroup\$ – xnor Jul 24 at 1:08

20 Answers 20

10
\$\begingroup\$

C (gcc), 179 176 157 152 149 bytes

-3 -3 bytes thanks to ceilingcat

-19 bytes thanks to xibu

L,M,P=543452769;f(s,t)typeof("")s,t;{M=M>>8|*s<<24;t=(M|'    '|L<<24)-P?t:memcpy(t-3,(typeof(0)[]){P,M|=1<<29,P,M,P},20)+19;L=M;(*t=*s)&&f(s+1,t+1);}

Try it online!

Assumptions

  • ASCII
  • Little-endian
  • sizeof(int) == 4
  • sizeof(int *) >= sizeof(char *) (I cannot imagine what absurd platform this would be false on, but you never know.)
  • typeof() provided by the compiler.

Breakdown

We step through the input string one character at a time. This character is placed at the top-most byte of M, shifting the previous characters to the left. This makes it so that M continuously holds a record of the four current characters. That's this part:

M=M>>8|*s<<24

Next up, we make M lower-case, and OR our fourth character with the previous character that we had before M. We compare the whole shebang with our magic number P, which represents the string "and ". Why ORing with the previous character like that? Well, it will only be true if that character was 0 (as in we are in the beginning of the string) or a space:

(M|'    '|L<<24)==P

If this is true, we know we have an "and" to deal with. We make sure the last character of M is a space and not NUL, and build an anonymous array of integers to copy into target string.

This array is built from noting that the word "and" (and whatever arbitrary case variant we picked out of the source string) will always be followed by a space (except for the last instance) when expanded to its final form, which means a neat four bytes, which happens to be the size of an integer. The string "and " is represented by P (little-endian makes the string appear reversed when viewed as a number):

M|=1<<29                        Make highest byte of M a space
t=memcpy(
    t-3                         Copy to sightly before target string
    ,(typeof(0)[]){P,M,P,M,P}   Integer array of "and " isotopes
    ,20)
+19                             Increment target string

Why to we copy to three bytes before the current target string? Because we have already copied those bytes before we knew it was an "and". And since this memcpy() is only ever called when we have found the keyword, we will never copy out of bounds.

The rest is straight-forward:

L=M;                            Last = Current
(*t=*s)&&f(s+1,t+1)             Copy byte and go to next bytes
                                in strings if not end-of-string
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ That is a great solution. I didn't expect an answer in C since 'char' is not allowed. That said typeof("") can be used instead of typeof(*"") because char[] will decay to char* whenever required. Using recursion and the multicharacter literals @ceilingcat suggested your function can be shortened to 154 Bytes without reading past the input string. \$\endgroup\$ – xibu Jul 24 at 20:10
  • \$\begingroup\$ @xibu Hm. I shall look into it. But the version you linked uses the forbidden letters, so it will be slightly longer. I did not get the typeof("") to work, since incrementing it would not work. Passing it recursively will of course work, though. \$\endgroup\$ – gastropner Jul 24 at 20:22
  • \$\begingroup\$ @gastropner your right, here is the solution without forbidden characters. \$\endgroup\$ – xibu Jul 24 at 20:35
  • \$\begingroup\$ @gastropner changing typeof(*"")*s,*t,*u; in your code to typeof("")s,t,u; works for me \$\endgroup\$ – xibu Jul 24 at 20:46
  • \$\begingroup\$ @xibu You are quite right! Don't know what step along the way I convinced myself it didn't work. \$\endgroup\$ – gastropner Jul 24 at 20:59
6
\$\begingroup\$

Perl 5 + -p -040 -l, 35 bytes

This script contains unprintables so the link is to a Bash program that builds the script and runs the tests.

$s= ~'...';s/^$s$/$s $& $s $& $s/gi

Try it online!

Explanation

Uses Perl s///ubstitution operator, but necessitates that and is built outside due to the source restriction. To create and, the $s is set to ~"\x9e\x91\x9b" using the raw bytes (hence using xxd). I started with "\x61\x6e\x64" and tried to look for shorter approaches. I also looked at PWQ^"195" and variants of that, and v97.110.100, but ~ was shortest. Once that string is created, it's possible to s///ubstitute it surrounded by start and end anchors (^ and $) due to the -040 command-line switch which uses space (ASCII 32, octal 040) as the record separator (which is also stripped off by -l) making $_ equal just the words themselves, with case-/insensitivity, with the string ($s) and the matched string $& as required, /globally within the input.


Perl 5 + -p040l, 41 bytes

Without using RegEx. Link shows 50 bytes because I'm using the \xXX notation. Will fix when I'm not on mobile!

$s= ~"\x9e\x91\x9b";$_=lc eq$s?"$s $_ $s $_ $s":$_

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ I can see you've prepared this solution when it was still in the Sandbox, based on the . in the Mr. Anderson test case. I removed it when I just posted it to main, since I mentioned in the rules the input will only contain letters and space. ;) But well done. Looking forward to that explanation. \$\endgroup\$ – Kevin Cruijssen Jul 23 at 10:26
  • 1
    \$\begingroup\$ @KevinCruijssen Hah! I did spot it and played with it last night :P I Hope others enjoy this. I tried a few different attempts to get and but ended up with the slightly less interesting variant, but was fun experimenting with ways to make it. \$\endgroup\$ – Dom Hastings Jul 23 at 10:30
5
\$\begingroup\$

05AB1E, 18 bytes

-(3+1) from Kevin Cruijssen, -1 from ovs, -1 from Neil's Charcoal answer.

#εÐl'€ƒQils‚5∍]˜ðý

Try it online!

Explanation

#                   Space split
 ε                  Map:
  Ð                     Triplicate
   l                    lowercase
    '€ƒQ                == "and"?
        i               If true:
         l                  Lowercase
          s‚                Paired with original
            5∍]             Extend to 5 items
                       (Else: return the current item)
               ˜   Flatten
                ðý Join by spaces
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Nice answer. Some things to golf: the I# can be Ð (Duplicate is indeed not allowed, but triplicate is still available); and the ε and } can be removed, since l'€ƒQ vectorizes the list automatically. \$\endgroup\$ – Kevin Cruijssen Jul 23 at 11:48
  • 1
    \$\begingroup\$ Instead of modifying the current word you can intersperse () ["and", "and", "and"] with it, flatten the list, and the use the final join to add the spaces: #Ðl'€ƒQÅÏ'€ƒ3иs.ý}˜ðý \$\endgroup\$ – ovs Jul 23 at 12:15
  • 1
    \$\begingroup\$ Nice new approach. You can golf 1 more byte by changing the Þ5£ to 5∍ \$\endgroup\$ – Kevin Cruijssen Jul 23 at 12:57
5
\$\begingroup\$

Python 3.8, 102 bytes

k=iⁿput().split();o=[]
while k:w,*k=k;o+=([w],[x:=w.lower(),w,x,w,x])["\x61\x6e\x64"==x]
priⁿt(*o)

Try it online!


Python 3.8, 106 104 bytes

-2 bytes inspired by this answer from Luis Mendo.

exec('priⁿt(*sum([([x:=w.lower(),w,x,w,x],[w])["\x61\x6e\x64"!=x]for w i\x6e iⁿput().split()],[]))')

Try it online!

Deobfuscated Code:

priⁿt(*sum([([x:=w.lower(),w,x,w,x],[w])["and"!=x]for w in iⁿput().split()],[]))
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ The "deobfuscated code" is more minimal? Only 80 bytes? mothereff.in/byte-counter \$\endgroup\$ – Protector one Jul 24 at 13:04
  • 1
    \$\begingroup\$ @Protectorone but that has prohibited characters :) \$\endgroup\$ – Mathias711 Jul 24 at 13:43
  • \$\begingroup\$ Aaah, now I see! 👍 \$\endgroup\$ – Protector one Jul 24 at 13:55
4
\$\begingroup\$

Python 3, 160 151 149 bytes

q='\141\156\144'
l='=l\141mb\144\141 x:'
exec(f"f{l}x {q} x[0]+((q+x[:5])*2+q+f(x[4:])if' {q} '==x[:5].lower()else f(x[1:]));g{l}f(' '+x+' ')[1:-1]")

Try it online!

Since xnor said it would take imagination I've gone ahead and done a python answer. It is more of a proof of concept than anything else since I am quite rusty on python golf.

Explanation

I wrote the pretty straightforward code:

q='and'
f=lambda x:x and x[0]+((q+x[:5])*2+q+f(x[4:])if' and '==x[:5].lower()else f(x[1:]))
g=lambda x:f(' '+x+' ')[1:-1]

Which would solve the problem if it were not for the character restriction. Then to get around the restriction I used exec with escape codes on all the problematic characters.

exec("q='\141\156\144';f=l\141mb\144\141 x:x \141\156\144 x[0]+((q+x[:5])*2+q+f(x[4:])if' \141\156\144 '==x[:5].lower()else f(x[1:]));g=l\141mb\144\141 x:f(' '+x+' ')[1:-1]")

And since and appeared in the original source 3 times, I moved the definition of q outside the exec and inserted q in those places to save bytes. I also wrote a substitution for =lambda x: since it appears twice.

q='\141\156\144'
l='=l\141mb\144\141 x:'
exec(f"f{l}x {q} x[0]+((q+x[:5])*2+q+f(x[4:])if' {q} '==x[:5].lower()else f(x[1:]));g{l}f(' '+x+' ')[1:-1]")
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ I think this doesn't handle and's at the start and end unfortunately. \$\endgroup\$ – xnor Jul 24 at 1:11
  • \$\begingroup\$ @xnor Thanks, it's a bit of an odd requirement. I've fixed it now. \$\endgroup\$ – Wheat Wizard Jul 24 at 1:17
4
\$\begingroup\$

Dyalog APL, 99 95 93 92 39 bytes

(7⍴'\b',⎕ucs 65 78 68)⎕R(15⍴'\l& & ')⍠1

Try it online!

Golfed ... a lot of bytes thanks to @Adám

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Could you perhaps add a Try it online link with test cases, if that's possible for Dyalog APL? If not, could you perhaps add a screenshot of the reset as verification? \$\endgroup\$ – Kevin Cruijssen Jul 24 at 17:14
  • 1
    \$\begingroup\$ Thanks, I have added the TIO link! \$\endgroup\$ – Ada Jul 24 at 17:22
  • 1
    \$\begingroup\$ Thank you! :) I had already upvoted your answer earlier, but it indeed seems to work as intended, as expected. \$\endgroup\$ – Kevin Cruijssen Jul 24 at 17:32
  • 1
    \$\begingroup\$ Golfed some bytes: (7⍴'\b',⎕ucs 65 78 68)⎕R(15⍴'\l& & ')⍠1 Try it online! \$\endgroup\$ – Adám Jul 27 at 6:52
  • \$\begingroup\$ Thank you Adám! \$\endgroup\$ – Ada Jul 27 at 18:51
3
\$\begingroup\$

PHP, 97 bytes

Saved 17 bytes thanks to Dom Hastings

<?php $b=chr(97);$c=XWT^"990";echo(preg_repl.$b.ce)("/\b$c\b/i","$c \\0 $c \\0 $c",${$b.rgv}[1]);

Try it online!


PHP, 114 bytes

<?php $b=chr(97);$c=$b.chr(110).chr(100);$e=preg_repl.$b.ce;echo$e("/\b($c)\b/i","$c \\1 $c \\1 $c",${$b.rgv}[1]);

Try it online!

Ungolfed

<?php

$b = chr(97);
$c = $b . chr(110) . chr(100);
$e = "preg_repl{$b}ce";

echo $e("/\b($c)\b/i", "$c \\1 $c \\1 $c", ${$b . "rgv"}[1]);

chr(97) resolves to 'a', chr(110) to 'n', and chr(100) to 'd'.

PHP allows you to define a variable as a string, then execute a function with the standard function syntax. e.g.:

$d = 'print';
$d('hello world'); // Parsed as print('hello world');

Using this I am able to execute the preg_replace function by interpolating the chr(97) from earlier and run a case insensitive regex to perform the necessary operation.

The final issue comes from input variables in PHP being e.g. $argv[1] - and they're always argv. Fortunately PHP has a variable variable syntax, so ${'argv'} is the same as $argv - so I simply concatontate my chr(97) to 'rgv' and execute in variable variable syntax.

Finally, a few bytes are saved by using PHP's assumptions. An unquoted string is how to reference a constant in PHP. Undefined constants are assumed to be their own name.

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Nice work! You can save a few bytes though: you don't need to define $e=preg_repl.$b.ce, you can just use echo(preg_repl.$b.ce)(...) directly. You can avoid the capture ($c) in your regex and use \\0 to get the contents instead. You can also use stringwise XOR to get and via $c=XWT^"990" (or many other strings!) and either $b=$c[0] or $b=X^"9" to get the a. I can't find a way to get it working on without calling PHP manually via Bash, but you should be able to use -R to skip the <?php and use $argn instead of $argv[1] for some more savings, but that might be too far! \$\endgroup\$ – Dom Hastings Jul 23 at 11:42
  • 1
    \$\begingroup\$ @DomHastings Thanks for the pointers! I don't golf enough to know all the tricks yet :) The directly calling preg_replace as a string occurred to me but the specific syntax eluded me and I foolishly assumed it was impossible, Also the quotes around "rgv" are only there in my ungolfed version. \$\endgroup\$ – Scoots Jul 23 at 11:49
  • 1
    \$\begingroup\$ Entirely possible, I may have made an edit or 12 :) \$\endgroup\$ – Scoots Jul 23 at 11:52
  • 1
    \$\begingroup\$ In fact, just removing the variable $b and doing (preg_repl.$c[0].ce) and ${$c[0].rgv}[1] should save you more 2 bytes. The final code will be: <?$c=XWT^"990";echo(preg_repl.$c[0].ce)("/\b$c\b/i","$c \\0 $c \\0 $c",${$c[0].rgv}[1]); (88 bytes). You can try it on: sandbox.onlinephpfunctions.com/code/… (Also, if you use php -r, you might save more bytes) \$\endgroup\$ – Ismael Miguel Jul 24 at 9:20
  • 1
    \$\begingroup\$ By the way, if you decide to do not use php -r (don't have how to test it, and the Try It Online website is horrible to use) you can just do this instead: <?=(preg_repl.($c=XWT^"990")[0].ce)("/\b$c\b/i","$c \\0 $c \\0 $c",${$c[0].rgv}[1]); which reduces the code to 84 bytes. <?= is the same as <?php echo. \$\endgroup\$ – Ismael Miguel Jul 24 at 9:41
3
\$\begingroup\$

JavaScript (ES6),  76 74  73 bytes

Saved 1 byte thanks to @tsh

s=>s.repl\u0061ce(/\b\x61\x6e\x64\b/gi,(x=(y='\x61\x6e\x64')+' $& ')+x+y)

Try it online!

Without escaped characters, this simply reads as:

s=>s.replace(/\band\b/gi,(x=(y='and')+' $& ')+x+y)
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ s["repl\x61ce"] -> s.repl\u0061ce \$\endgroup\$ – tsh Jul 24 at 2:06
  • \$\begingroup\$ @tsh I did not think about that one. Thank you! \$\endgroup\$ – Arnauld Jul 24 at 2:11
3
\$\begingroup\$

sed, 70 \$\cdots\$ 56 52 bytes

Saved 4 bytes thanks to Dom Hastings!!!

s/\b\x61\x6e\x64\b/& \0 & \0 &/Ig;s/&/\x61\x6e\x64/g

Try it online!

Swaps all occurances of and (which is written in escaped hex as \x61\x6e\x64) in any case surrounded by word boundaries (\b) with: a ampersand (&), followed by that occurance, another ampersand, that occurance again, and finally a third ampersand. Since all input only contains spaces and letters, any ampersands present are there because of those swaps. So they're all replaced with and (\x61\x6e\x64) to complete the process.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ +1. Good old RegEx! I don't know much about sed, but you should able to save a couple of bytes removing the capturing parens and using \0 instead of \1 in the replacement! \$\endgroup\$ – Dom Hastings Jul 24 at 5:41
  • \$\begingroup\$ @DomHastings Nice one - thanks! :-) \$\endgroup\$ – Noodle9 Jul 24 at 9:04
3
\$\begingroup\$

Excel, 437 435

Closing quotes and parens already discounted. It's not pretty, but I found some surprising optimizations.

Setup

Input: C1

Cells B1 to B9 (One cell per row).

 [SPACE]
=B1&LEFT(RIGHT(TEXT(,"[$-33]MMMM"),4),3)&B1
=UPPER(B2)
=LEFT(B2,2)&RIGHT(B3,3)
=LEFT(B2,3)&RIGHT(B3,2)
=LEFT(B3,3)&RIGHT(B2,2)
=LEFT(B3,2)&RIGHT(B5,3)
=PROPER(B2)
=LEFT(B2,2)&RIGHT(B6,3)

Cells C2 to C9

=SUBSTITUTE(B1&C1&B1,B2,REPT(B2,5))
=SUBSTITUTE(C2,B3,B2&B3&B2&B3&B2)
=SUBSTITUTE(C3,B4,B2&B4&B2&B4&B2)
=SUBSTITUTE(C4,B5,B2&B5&B2&B5&B2)
=SUBSTITUTE(C5,B6,B2&B6&B2&B6&B2)
=SUBSTITUTE(C6,B7,B2&B7&B2&B7&B2)
=SUBSTITUTE(C7,B8,B2&B8&B2&B8&B2)
=TRIM(SUBSTITUTE(C8,B9,B2&B9&B2&B9&B2))

...where C9 is the final output.

How It Works

  • B2 - TEXT() creates the text "Phando" (EN January) in Venda, an official language of South Africa. The rest of it extracts the "and" from it and surrounds it with spaces.
  • The rest of the Cells in Column B simply enumerate all possible capitalizations of "and".
  • C2 - We first surround the input with spaces so edge handling is easier. Then replace "and" with 5 of itself.
  • After this, the rest of the cells in column C replace occurrences of the corresponding capitalization permutation in column B with the sandwiched string.
  • In the last cell, trim off the surrounding spaces.

Note

  • Nesting the C's gives us no advantage because we trade off the equals sign for the auto-closed parens.
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Japt, 22 21 bytes

Work in progress

r`%ß@%b`È3ÇXvÃqXû5}'i

Try it

Original (w/ -S flag)

¸cÈv ¶`ß@`Å?5ogX¸iXv:X

Try it

¸cÈv ¶`ß@`Å?5ogX¸iXv:X     :Implicit input of string
¸                          :Split on spaces
 c                         :Map then flatten
  È                        :Passing each X through the following function
   v                       :  Lowercase
     ¶                     :  Test for equality with
      `ß@`                 :    The compressed string "band" ("and" compressed is also 2 bytes but includes the "d")
          Å                :    Slice off the first character
           ?               :  If true
            5o             :    Range [0,5)
              g            :    Index (0-based) each into
               X¸          :      Split X on spaces, converting it to a single element array
                 i         :      Prepend
                  Xv       :        Lowercase X
                    :X     :  Else return X
                           :Implicit output joined by spaces
| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Jelly,  23 22 21  20 bytes

Note: ɗ is not a d!

Ḳ,@ṁ5Kɗ€Œlẹ¥¦“2ɼ»Ṗ¤K

A monadic Link accepting a list of characters which yields a list of characters.

Try it online!

How?

Note: and is not in Jelly's dictionary, and its compression is “¡ÞṄɱ» which we could use, but I decided to go with “2ɼ»Ṗ¤ which is also five bytes.

Ḳ,@ṁ5Kɗ€Œlẹ¥¦“2ɼ»Ṗ¤K - Main Link: list of characters, S
Ḳ                    - split (S) at spaces -> list of words
                     - (implicitly set the right argument to:)
                  ¤  -   nilad followed by link(s) as a nilad:
             “2ɼ»    -     compression of "andy"
                 Ṗ   -     pop -> "and"                         - 
            ¦        - sparse application...
           ¥         - ...indices: last links as a dyad - f(words, "and")
        Œl           -               lower-case (all the words)
          ẹ          -               indices of ("and" in the lower-cased words)
      ɗ€             - ...action: last three links as a dyad for each - f(word,"and"):
  @                  -               with swapped arguments:
 ,                   -                 pair -> ["and", word]
   ṁ5                -                 mould like five -> ["and", word, "and", word, "and"]
     K               -                 join with spaces
                   K - join with spaces
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ There you go @KevinCruijssen hope it all makes sense. \$\endgroup\$ – Jonathan Allan Jul 23 at 12:14
  • \$\begingroup\$ Thanks for the heads up. :) Out of curiosity: why isn't and in the dictionary? Jelly has a huge dictionary (how many words does it contain actually? - 05AB1E has 10,000 exactly), so a bit weird such a common word is missing. Does it have to do with the small length that would be rather similar in size uncompressed? \$\endgroup\$ – Kevin Cruijssen Jul 23 at 12:42
  • \$\begingroup\$ @KevinCruijssen the words are just those which were in Dennis' linuxwords file at the time I believe; 'AND' is in there though. There are almost 250K words in there. \$\endgroup\$ – Jonathan Allan Jul 23 at 13:04
2
\$\begingroup\$

Haskell, 177 bytes

r x|_:z:_<-[x..]=z
(#)=elem.r
f(b:t@(c:e:g:h:s))|u<-b:c:e:g:" ",[b,h]<" !",c#"bB",e#"oO",g#"eE",i<-r<$>"`mc"=b:i++u++i++u++i++f(h:s)
f" "=""
f(b:t)=b:f t
g x|_:y<-f$' ':x++" "=y

Try it online!

Explanation

r takes a character and returns the next character in ASCII order. That is to say its successor.

Then we use this to make (#) which takes a character and a list and checks if that character's successor is in the list.

Then we use that to make f.

Many of the functions I would really like to use from Haskell are missing.

More boring version, 174 bytes

(#)=elem
f(b:t@(c:e:g:h:s))|u<-b:c:e:g:" ",[b,h]<" !",c#"\65\97",e#"\78\110",g#"\68\100",i<-"\97\110\100"=b:i++u++i++u++i++f(h:s)
f" "=""
f(b:t)=b:f t
g x|_:y<-f$' ':x++" "=y

Try it online!

This version forgoes using r to generate forbidden characters and instead escapes them. Boring but saves 3 bytes.

| improve this answer | |
\$\endgroup\$
2
\$\begingroup\$

Scala 2.12, 126 116 bytes

"(?i)(\\b\u0061\u006e\u0064\\b)".r repl\u0061ce\u0041llI\u006e(_,m=>{v\u0061l x=m+""toLowerC\u0061se;s"$x $m "*2+x})

You do need to assign that function to a variable of type String => String, though, and enable postfix operators (to save 1 byte). This adds 21 more characters.

def f:String=>String="(?i)(\\b\u0061\u006e\u0064\\b)".r repl\u0061ce\u0041llI\u006e(_,m=>{v\u0061l x=m group 0 toLowerC\u0061se;s"$x $m $x $m $x"})

After Scala 2.13, you need to use backticks around variable names when using unicode escapes, hence Scala 2.12.2.

Try it online

Prettier version

val f: String => String = s => 
  raw"(?i)(\band\b)".r.replaceAllIn(s, 
    m => {
      val x = m.group(0).toLowerCase
      s"$x $m $x $m $x"
    })
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ That def has a d. \$\endgroup\$ – xnor Jul 23 at 21:56
  • \$\begingroup\$ @xnor Didn't notice that! Fixed now, but had to add 5 extra characters :( \$\endgroup\$ – user Jul 23 at 22:51
2
\$\begingroup\$

GNU sed, 38 bytes

s/\<\c!\c.\c$\>/\L&\E & \L&\E & \L&/Ig

"and" is written escaped as \c!\c.\c$. \cx means take the character x, convert it to upper case if it is a lower case letter, and then flip bit 6. The surrounding \< and \> mean word boundaries. & corresponds to the matched string. \L switches to lowercase, and \E switches back. The I modifier means ignore case when matching. The g modifier means replace all matches, not just the first.

Try it online!

| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ Nice answer (based on the description). Could you perhaps add a try it online link with the test cases, assuming the language sed from the list is the one you've used. If GNU sed is not available on TIO, could you perhaps add a screenshot as verification for the answer instead? Oh, and welcome to CGCC! :) Nice first answer. \$\endgroup\$ – Kevin Cruijssen Jul 24 at 20:09
  • 1
    \$\begingroup\$ @KevinCruijssen Thanks. I added the TIO link, as requested. Nowadays, sed pretty much means GNU sed, and it seems to work in the TIO environment. \$\endgroup\$ – RobertR Jul 24 at 20:20
  • 1
    \$\begingroup\$ Thanks for adding it, all seem to work fine, as expected. I had already upvoted, so I can't do it again. Good luck with future challenges, and enjoy your stay! :) \$\endgroup\$ – Kevin Cruijssen Jul 24 at 20:35
1
\$\begingroup\$

Charcoal, 29 bytes

≔“1“$K”η⪫E⪪S ⎇⁼↧ιη⪫⟦ηιηιη⟧ ι 

Try it online! No verbose mode because it won't "compress" the string for me. Explanation:

≔“1“$K”η

Assign the compressed string and to a variable. (None of the various ways of compressing the string and uses a banned letter; this is just the shortest option, after banning the uncompressed string.)

   S                    Input string
  ⪪                     Split on literal space
 E                      Map over words
        ι               Current word
       ↧                Lowercased
      ⁼                 Equals
         η              "and"
     ⎇                  If true then
           ⟦ηιηιη⟧      Alternate lowercase and original word
          ⪫             Join with literal space
                   ι    Otherwise the original word
⪫                       Join everything with literal space
                        Implicitly print
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Pip -s, 34 bytes

Y Jz@[i13 3]{(gPEyLC@gQy?,5o)}Mq^s

Try it online!

Explanation

Non-regex solution taking advantage of the "letters and spaces only" rule. Partially inspired by Jonathan Allan's Jelly answer.

Y Jz@[i13 3]{(gPEyLC@gQy?,5o)}Mq^s
                                    z is lowercase alphabet; i is 0; o is 1 (implicit)
   z@[i13 3]                        Get the lowercase letters at indices 0, 13, and 3
  J                                 Join them into the string "and"
Y                                   Yank that into the variable y
                               q    Read a line of input from stdin
                                ^s  Split on spaces
            {                }M     Map this function:
              g                      The list of arguments: [word]
               PEy                    with y prepended: ["and" word]
             (              )        Index this list with the following index:
                        ?             If
                    @g                 the first argument
                  LC                   lowercased
                      Qy               equals y
                         ,5           then range(5)
                           o          else 1

Here's what the indexing does: If the word we're processing is some case-variant of "and", we get the first five elements of the list ["and" word]. With cyclic indexing, this amounts to ["and" word "and" word "and"]. If the word is some other word, we get the element at index 1, which is just word.

The result is a (possibly nested) list, which the -s flag joins on spaces and then autoprints. An example run:

q       "Stand aNd  watch"
q^s     ["Stand" "aNd" "" "watch"]
{ }Mq^s ["Stand" ["and" "aNd" "and" "aNd" "and"] "" "watch"]
Output: Stand and aNd and aNd and  watch

Pip, 34-bytes (no flags)

Y Jz@[i13 3]qR-:yWR`\b`yWR` & `WRy

Try it online!

Explanation

My initial solution using regex:

Y Jz@[i13 3]qR-:yWR`\b`yWR` & `WRy
                                    z is lowercase alphabet; i is 0 (implicit)
   z@[i13 3]                        Get the lowercase letters at indices 0, 13, and 3
  J                                 Join them into the string "and"
Y                                   Yank that into the variable y
            q                       Read a line of input from stdin
             R                      In that string, replace
                y                    the string "and"
                 WR`\b`              wrapped in the regex `\b`: `\band\b`
              -:                     with the case-insensitive flag set: `(?i)\band\b`
                                    with
                       y             the string "and"
                        WR` & `      wrapped in the regex ` & `: ` & and & `
                               WRy   wrapped in the string "and": `and & and & and`
                                     (where & in replacement context stands for the
                                     full match)
                                    Autoprint (implicit)
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Stax, 32 26 bytes

å╔é╩⌐╬²ßxæ╬:Ö5ò▌@ Θ5YS₧Ñπε

Run and debug it

I knew packed stax mutation was good for something.

Saved 6 bytes thanks to an anonymous donor.

| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Wolfram Language (Mathematica), 116 112 bytes

-4 bytes thanks to att!

Stri\.6egRepl\.61ce[a:Regul\.61rExpressio\.6e["(?i)\\b"<>#<>"\\b"]:>Stri\.6egRiffle@{#,a,#,a,#}]&@"\.61\.6e\.64"

Try it online! An expression that evaluates to a function. Uses the standard regex (?i)\band\b. For reference, the shortest equivalent function that doesn't use a regex is 118 bytes:

Stri\.6egRepl\.61ce[a=WordBou\.6ed\.61ry;a~~b:#~~a:>Stri\.6egRiffle@{#,b,#,b,#},Ig\.6eoreC\.61se->1>0]&@"\.61\.6e\.64"
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ 112 bytes \$\endgroup\$ – att Jul 30 at 20:16
1
\$\begingroup\$

Lua, 151 bytes

b="\97\110\100"_G["lo\97\100"]('pri\110t(\97rg[1]:gsub("%w+",fu\110ctio\110(s)retur\110 s:lower()==b '..b..' (b.." "..s.." "):rep(2)..b e\110\100))')()

Try it online!

How It Works

b is a string which is equal to "and" via ASCII escape codes.

_G in Lua is the "global environment table", the data structure containing all global variables. We can index this with a string, which can contain ASCII codes for the forbidden letters.

load() returns a function from the string passed to it (which we immediately call). Again, ASCII codes are used here for forbidden characters.

arg is the command-line arguments table

gsub() is a Global SUBstitution function, it takes a pattern (in this case a sequence of 1 or more alphanumeric characters) and replaces it according to the second parameter, in this case an anonymous function which it calls for every match.

and is a boolean operator which return the right-hand-side of the operation or false.

rep() is a string repetition function.

Readable Version

-- Match Every Word, Replacing Any "and"s
print(arg[1]:gsub("%w+",function(s)
    return s:lower() == "and" and ("and "..s.." "):rep(2).."and"
end))
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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