56
\$\begingroup\$

In an earlier challenge I asked code golfers to produce strings which copy each character in a string. For example:

TThhiiss iiss ddoouubbllee ssppeeaakk!! 

This challenge is simply to detect if some text meets the definition of a double speak string.

  • There is an even number of characters.
  • When split into pairs, every pair consists of two of the same character.

The challenge

  • It's code golf, do it in few bytes.
  • Use any language you choose.
  • Please include a link to an online interpreter.
  • The code will accept some text.
  • For simplicity, the input will only consist of printable ASCII characters
  • It will return an indication of whether or not the input is double speak. It could be:
  • A boolean
  • Strings ('true', 'false', 'yes', 'no' etc)
  • Integers 0 or 1

Test Cases:

input -> output aba -> false aab -> false abba -> false aabb -> true aaabb -> false tthhiiss -> true ttthhhiiisss -> false 
\$\endgroup\$
12
  • 9
    \$\begingroup\$ May we error on inputs of length < 2? \$\endgroup\$ Commented Aug 6, 2019 at 16:06
  • 4
    \$\begingroup\$ Suggested test case: abba which should be falsey \$\endgroup\$ Commented Aug 6, 2019 at 16:29
  • 3
    \$\begingroup\$ Suggested test case: aabbbb which should be truthy \$\endgroup\$ Commented Aug 6, 2019 at 17:30
  • 2
    \$\begingroup\$ @val Well, I'm not going to argue with standard I/O \$\endgroup\$ Commented Aug 7, 2019 at 8:27
  • 4
    \$\begingroup\$ What about the empty string? \$\endgroup\$ Commented Aug 7, 2019 at 21:04

102 Answers 102

2
\$\begingroup\$

Kotlin, 56 52 bytes

{it.chunked(2).filter{it.toHashSet().size>1}.size<1} 

Try it online!

Thank you Khuldraeseth na'Barya for saving 4 bytes

\$\endgroup\$
1
  • \$\begingroup\$ Save a handful. Welcome to the site! \$\endgroup\$ Commented Aug 6, 2019 at 20:19
2
\$\begingroup\$

C (gcc), 50 bytes

Returns 0 if double-speak (or empty string), truthy otherwise.

f(s,i)char*s;{for(i=*s;i&(i=*s++)&&i==*s++;);s=i;} 

Try it online!

If the input string is assumed to always be at least 2 characters (gives incorrect result for single-character strings):

C (gcc), 38 bytes

f(char*s){while(*s&&*s++==*s++);s=*s;} 

Try it online!

\$\endgroup\$
4
  • \$\begingroup\$ The second suggestion seems to treat single character strings the same as any other odd length strings? \$\endgroup\$ Commented Aug 8, 2019 at 7:30
  • \$\begingroup\$ Wouldn't putting s=i at the end of for braces (for(i=*s;i&(i=*s++)&&i==*s++;s=i) save you one ;? \$\endgroup\$ Commented Aug 8, 2019 at 17:47
  • \$\begingroup\$ @PrzemysławCzechowski s=i is used to return the value: it's not part of the loop. I'm using i to capture the character value, so assigning it to s during the loop would mess up the pointer (and likely crash the program!) \$\endgroup\$ Commented Aug 8, 2019 at 18:04
  • \$\begingroup\$ @ErikF my bad, I thought s=i is repeated in every iteration. \$\endgroup\$ Commented Aug 8, 2019 at 18:23
2
\$\begingroup\$

Pip, 31 bytes

a:qFb,#a{b%2?x(ab+1)Qa@b?xi:1}i 

Try it online!

slightly different approach with fold operator, 31 bytes

a:qFb,#a{I!b%2i:$Q[a@b(ab+1)]}i 

outputs 0 if double speak, 1 otherwise

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

Perl 6, 14 bytes

{!S:g/(.)$0//} 

Try it online!

Replaces all pairs of identical characters with nothing and then boolean NOTs the result to return true if is an empty string (i.e. all characters were next to an identical one), or false otherwise.

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

PHP, 51 50 38 bytes

echo preg_match("/^((.)\2)+$/",$argn); 

Checks whether input matches pairs of chars where the chars in each pair are the same (using back ref).

Run like this:

echo 'dd00uubbllee' | php -nR 'echo preg_match("/^((.)\\2)+$/",$argn);';echo 
  • -1 byte thanks to @manatwork
  • -12 bytes by using preg_match with back references.
\$\endgroup\$
2
  • \$\begingroup\$ Wouldn't /.(.?)/ be enough to handle odd length strings? \$\endgroup\$ Commented Aug 8, 2019 at 9:29
  • \$\begingroup\$ @manatwork you're right, thanks \$\endgroup\$ Commented Aug 8, 2019 at 9:32
2
\$\begingroup\$

PHP, 37 40 bytes

+3 bytes to fix '0' issue

<?=''==preg_replace('/(.)\1/','',$argn); 

Try it online!

Similar to other RegEx answers.


PHP, 55 bytes

for(;($l=$argn[$i++])==$argn[$i++]&&$l.$l;);echo$l==''; 

Try it online!

Loops to the end of the string as long as every even character (0th, 2nd, 4th, etc ...) is equal to the character after it, else stops the loop. Finally, checks if it has arrived at the end of the string, which means the string is a double speak.


Outputs 1 for double speak and nothing for not double speak.

\$\endgroup\$
2
  • \$\begingroup\$ Your first one is close, but it negates the resulting string. "0" is falsey in PHP, so an input of "000" will be deemed doublespeak \$\endgroup\$ Commented Aug 8, 2019 at 9:59
  • \$\begingroup\$ @aross: Thanks for pointing it out, yeah that '0' == false is always an issue. Fixed! \$\endgroup\$ Commented Aug 8, 2019 at 11:38
2
\$\begingroup\$

Java (JDK), 64 bytes

s->{int i=s.length;for(;i>1;)i=s[--i]==s[--i]?i:i|1;return i<1;} 

Try it online!

Explanations

s->{ int i=s.length; for(;i>1;) // while the length is 2 or greater. i=s[--i]==s[--i]?i:i|1; // check the 2 previous values. If they're identical, don't do anything. Else, make i odd so that it fails at the return. return i<1; // i will be 0 only when the size is even and all characters were doubled. } 
\$\endgroup\$
2
\$\begingroup\$

Stax, 6 5 bytes

╩3╦x╨ 

Run and debug it at staxlang.xyz!

Outputs integers. Zero for double speak and nonzero (one now!) otherwise, as allowed here. Replace 1I below with |e if you want the opposite behavior, but I think this version looks nicer.

Unpacked (6 bytes) and explanation

:G|g1I :G Array of run lengths |g GCD 1I Is odd? Could use 2% instead 

The GCD of run lengths will be even exactly when all run lengths are.

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

Pushy, 13 bytes

LL2%}2/:=};P# 

Try it online!

 L \ Push len(input) L2% \ Take (len(input) + 1) % 2. This will be 1 only if the input had even length. } \ Move this to the bottom of the stack for later. 2/: ; \ Length of original input, divided by 2, times do: = \ Pop top two characters, and check equality. (Pushes 0 or 1) } \ Move this to the bottom of the stack for later. P \ Push the stack's product. If the input had odd length, or any two characters \ did not match, then the stack will contain a 0, so the product will be 0. \ Else, it will be 1. # \ Print the product. 
\$\endgroup\$
2
\$\begingroup\$

naz, 50 bytes

2a2x1v1x1f1r3x1v2e2x2v1r3x2v1e0m1o0x1x2f0m1a1o0x1f 

Works for any input string, provided it's passed as a file terminated with the control character STX (U+0002).

Explanation (with 0x commands removed)

2a2x1v # Set variable 1 equal to 2 1x1f1r3x1v2e # Function 1 # Read a byte and jump to function 2 if it equals variable 1 2x2v # Otherwise, store it in variable 2 1r3x2v1e # Read another byte # Jump back to the start of function 1 if it equals variable 2 0m1o # Otherwise, output 0 1x2f0m1a1o # Function 2 # Output 1 1f # Call function 1 
\$\endgroup\$
2
\$\begingroup\$

Burlesque, 8 bytes

J2en)J== 

Try it online!

 [AABBCC] [ABC] J #Duplicate [AABBCC,AABBCC] [ABC,ABC] 2en #Every other character [AABBCC,ABC] [ABC,AC] )J #Duplicated [AABBCC,AABBCC] [ABC,AACC] == #Is the same [1] [0] 

Burlesque, 11 bytes

=[{L[2dv}al 

Try it online!

=[ # Group consecutive like values { L[ # Length of (group) 2dv # Divisible by 2 }al # All 
\$\endgroup\$
2
\$\begingroup\$

Marbelous, 84 bytes

No output for false, output one \u0000 for true using this standard I/O rule

@0@1 0000 ]]]]&101 eqal\\&1 @0@1..=0\/ :eqal @0..@1 }0..}1 --..-- <1&0<1&0 {0@0{1@1 

interpretor

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

JavaScript (Node.js), 23 bytes

z=>/^((.)\2)+$/.test(z) 

Uses a regular expression that match two of the same characters one or more times

Try it online!

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

Risky, 5 bytes

0?/20_?:? 

Try it online!

Doesn't work with the empty string; OP hasn't clarified if that's a problem.

Explanation

0 transpose ? input / split into groups of 2 2 0 reduce _ ? accumulator : = ? item 
\$\endgroup\$
2
\$\begingroup\$

PHP4 (45 chars)

Given $argv[1] as a command line argument :

echo preg_match('#^((.)\2)*$#',$argv[1])?1:0; 

The script will output 0 or 1 to answer.

PHP7.4 (41 chars)

The $f arrow function will return the answer :

$f=fn($s)=>preg_match('#^((.)\2)*$#',$s); 

C gcc (27 chars)

Function f today return an indication of whether or not the input is double speak :

f(char*s){1[s]-*s||f(s+2);} 

Usage :

#include <stdio.h> int main() { printf("EXPECT %5s ... %-5s .. aba\n","NO", f("aba")?"NO":"YES"); printf("EXPECT %5s ... %-5s .. abba\n","NO", f("abba")?"NO":"YES"); printf("EXPECT %5s ... %-5s .. aabb\n","YES", f("aabb")?"NO":"YES"); printf("EXPECT %5s ... %-5s .. aaabb\n","NO", f("aaabb")?"NO":"YES"); printf("EXPECT %5s ... %-5s .. tthhiiss\n","YES", f("tthhiiss")?"NO":"YES"); printf("EXPECT %5s ... %-5s .. ttthhhiiisss\n","NO", f("ttthhhiiisss")?"NO":"YES"); } 

Try it Online

C Variants :

g(char*s){s=*s&&g(s+2)+s[1]-*s;} // 32 chars h(char*s){return*s&&h(s+2)+s[1]-*s;} // 36 chars 
\$\endgroup\$
2
\$\begingroup\$

><> (Fish), 22 bytes

l2%?v>l?v1n; ;n0<^?=< 

Try it

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

X86_64/Linux Machine Code, 19-Bytes

Try it online!

Usage:

$> gcc -Wl,-Tbss=0x80000000 -DIDEAL_BSS -s -static -nostartfiles -nodefaultlibs -nostdlib -Wl,--build-id=none double-speak.S -o double-speak $> echo -n "<input> | ./double-speak; echo $? 

Program reads input from stdin (it is sensitive to the exact byte count of input, i.e stray spaces/new lines will change result).

Returns 0 for double-speak, and non-zero otherwise.

Notes:

  • Size is measured in machine code (i.e 19 bytes of PROGBITS; .text, .data, etc...)
  • The 19-byte size assumes the above compile command which sets the BSS address at an ideal value. With generic compile commands (no linker inputs), its 21-bytes.

Program:

/* Uncomment below if BSS was setup at 2^20. */ /* #define IDEAL_BSS */ .global _start .text _start: /* Incoming registers are zero. */ decl %edx #ifdef IDEAL_BSS btsl %edx, %esi #else movl $G_mem, %esi #endif /* eax == 0 == SYS_read. */ /* edi == 0 == STDIN. */ syscall xchgl %eax, %ecx loop: /* Load next pair. */ lodsw /* Need to decr by 2 each loop. */ decl %ecx /* Check that bytes match. */ xorb %ah, %al /* Break if ne or end of count. */ loope loop /* edi is zero (clears hi bits of eax). eax is zero if double- speak. Otherwise non-zero. */ xchgl %eax, %edi /* Exit. */ movb $60, %al syscall .section .bss G_mem: .space(4096 * 8) 

Example/Test:

$> for x in aba abba aabb aaabb tthhiiss ttthhhiiisss; do echo -n "${x}" | ./double-speak; echo "${x} -> $?"; done aba -> 3 abba -> 3 aabb -> 0 aaabb -> 3 tthhiiss -> 0 ttthhhiiisss -> 28 
\$\endgroup\$
2
\$\begingroup\$

TypeScript's Type System, 86 bytes

type F<S>=S extends`${infer C}${infer D}${infer R}`?C extends D?F<R>:0:S extends""?1:0 

Try it at the TypeScript playground!

This is a generic type F taking a string-literal type parameter S, and outputting 0 for non-double-speak and 1 for double-speak.

None of the test cases offer a case where all of the pairs are equal but the whole string is of odd length, which tripped me up a bit. This is likely golfable, maybe that last extends clause can be dropped with something clever.

Explanation:

type F<S> = // Match S to extract the first two chars C and D and the rest R S extends `${infer C}${infer D}${infer R}` // if it matched: is C the same type as D? ? C extends D ? F<R> // if so, recurse with R : 0 // otherwise, it's not double-speak; return 0 // if it didn't match, we check if the string is empty or has one character. : S extends "" ? 1 : 0 
\$\endgroup\$
2
\$\begingroup\$

JavaScript (Node.js), 26 bytes

f=([a,b,...c])=>a==b&&f(c) 

Attempt This Online!

Outputs via exit-code. I think this is really nice and clean but that's just my opinion. Unfortunately, this doesn't beat the tried-and-true regex.

Explanation:

  • f=([a,b,...c])=>...

    Makes a function f that destructures its string argument into the first character a, the second character b, and rest of the string c.

  • a==b&&f(c)

    Check if a is equal to b. The && (AND) operator only evaluates its right argument if its left is true, so if it is true we recurse with c.

    If a and b aren't equal, then it can't be double speak, so we stop recursion to output with a 0 exit code.

    If they're equal, we keep checking the next two until either

    • A) recursion stops because a isn't equal to b, or
    • B) a and b are both undefined because we've reached the end of the string and there are no more characters left, so we recurse until the recursion depth is hit, giving an exit code of 1.
\$\endgroup\$
1
\$\begingroup\$

Gema, 17 characters

?$1= ?=0@end \Z=1 

Outputs 1 on double speak and 0 on not.

Sample run:

bash-5.0$ echo -n 'TThhiiss iiss ddoouubbllee ssppeeaakk!!' | gema '?$1=;?=0@end;\Z=1' 1 

Try it online!

Gema, 12 characters

?$1= ?=@fail 

Terminates with exit code 0 on double speak and 2 on not.

Sample run:

bash-5.0$ echo -n 'TThhiiss iiss ddoouubbllee ssppeeaakk!!' | gema '?$1=;?=@fail' bash-5.0$ echo $? 0 

Try it online!

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

Kotlin, 59 57 bytes

{s->(0..s.length-1 step 2).fold(""){t,c->t+s[c]+s[c]}==s} 

Try it online!

-1 byte thanks to Khuldraeseth na'Barya

-1 byte changing it -> s


Slightly lazy attempt - basically just took my answer from the doublespeak question, applied it to every second char of the input and see if the result is the input.

\$\endgroup\$
2
  • \$\begingroup\$ Save a byte \$\endgroup\$ Commented Aug 6, 2019 at 19:25
  • \$\begingroup\$ @Khuldraesethna'Barya updated, thanks! did not know that was a thing \$\endgroup\$ Commented Aug 6, 2019 at 19:32
1
\$\begingroup\$

Kotlin, 4649 bytes

-3 bytes thanks to @cubic lettuce

{it.chunked(2).all{it.length>1&&it[0]==it[1]}} 

Try it online!

{it.length%2==0&&it.chunked(2).all{it[0]==it[1]}} 

Try it online!

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Save 3 bytes by {it.chunked(2).all{it.length>1&&it[0]==it[1]}} ;) \$\endgroup\$ Commented Aug 7, 2019 at 20:41
1
\$\begingroup\$

C (tcc), 59 55 50 bytes

f(char *s){while(*s==*++s)s++;return!*--s&&s!="";} 

Try it online!

Thanks to Jo King for the 4 bytes and Unrelated String for saving 5 bytes

Can it be even shorter?

\$\endgroup\$
8
  • \$\begingroup\$ *s==*++s, how is this not UB when *s points to the end of the string? \$\endgroup\$ Commented Aug 7, 2019 at 11:26
  • \$\begingroup\$ the *s will always point to the last character of the string given in argument which is not last character because string here ends with '\0' so the *++s gets the \0 \$\endgroup\$ Commented Aug 7, 2019 at 11:36
  • 1
    \$\begingroup\$ You increment s by two each time through the loop, so if there is an even number of actuall characters in the string I do not see how you can guarantee that *s never points to the '\0' \$\endgroup\$ Commented Aug 7, 2019 at 11:58
  • \$\begingroup\$ You could golf it considerably by replacing *--s=='\0' with the simple !*--s, but also note that most challenges require submissions to be either functions or full programs, and this is neither. \$\endgroup\$ Commented Aug 7, 2019 at 19:37
  • \$\begingroup\$ Thanks guys for helping shortening it and @Taemyr play with this code TIO I don't need to care if *s gets the \0 character cause then the *++s will get the first character from the string used in printf. \$\endgroup\$ Commented Aug 8, 2019 at 5:07
1
\$\begingroup\$

Rust, 73 bytes

|s:&str|!s.chars().enumerate().any(|(i,c)|s.chars().nth(i|1).unwrap()!=c) 

Try it online!

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

T-SQL 2012, 76 bytes

Looping using the following logic.

Finding the first match on the first character in the rest of the string.

If the match is on the second position, the first 2 characters are removed.

if the match is on a later position, character 0 to 1 is removed, resulting in null string.

If there are no matches, characters 3-4 are removed. Repeating this will eventually result in a null string.

The final string will be an empty string or a null string.

Empty string is "double speak"(1). Null string is not "double speak"(0).

DECLARE @ varchar(max)='ccbbddeeff' WHILE @>''SET @=stuff(@,-3/~charindex(left(@,1),@,2),2,'')PRINT iif(@=0,1,0) 

Try it online

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

JavaScript (Node.js), 26 bytes

s=>!s.replace(/(.)\1/g,'') 

Try it online!

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

C++ (gcc), 48 47 45 43 bytes

-2 bytes thanks to @ceilingcat
-2 bytes thanks to @JoKing

recursive function assuming zero terminated char table

int f(char*s){return!*s||*s==s[1]&&f(s+2);} 

Try it online!

\$\endgroup\$
3
  • \$\begingroup\$ @ceilingcat cool, I didn't now you can be that concise \$\endgroup\$ Commented Aug 9, 2019 at 8:02
  • \$\begingroup\$ @JoKing it works, there's just a warning because I'm using string literals to generate right kind of input - zero-terminated char* - which is not exactly legal in c++ but gcc allows it \$\endgroup\$ Commented Aug 9, 2019 at 8:26
  • \$\begingroup\$ Ah sorry, I thought the lack of output meant it wasn't working. 43 bytes \$\endgroup\$ Commented Aug 9, 2019 at 8:36
1
\$\begingroup\$

EDIT:

This solution is totally broken as demonstrated by the aabbbb test case. Thanks to @manatwork for pointing this out. Do not pass Go! Do not collect 200 dollars!

Bash and Gnu utils, 46 45 bytes

fold -1|uniq -c|grep -qv "2 "&&echo 0||echo 1 

Try it online!

-1 byte by skipping the first space in grep expression

\$\endgroup\$
3
  • \$\begingroup\$ Not sure if I can use grep exit codes and return output there? Instead of this &&echo 0||echo1 \$\endgroup\$ Commented Aug 9, 2019 at 9:32
  • 1
    \$\begingroup\$ This works fine on the question's test cases, but as I understand the challenge, it should output 1 on Khuldraeseth na'Barya's suggested test case, “aabbbb”. \$\endgroup\$ Commented Aug 9, 2019 at 9:34
  • \$\begingroup\$ @manatwork You're right. This solution is buggy in that sense. \$\endgroup\$ Commented Aug 9, 2019 at 11:23
1
\$\begingroup\$

Lua, 90 87 86 82 bytes

a,e=1,os.exit;(...):gsub('.',load's=...a=a~=1 and(a==s and 1 or e(1))or s')e(a==1) 

Try it online!

Take input as argument, use exit code as output.

Explanation

This is based on abusing few Lua features:

  • os.exit could accept either number, allowing short code for exit or boolean, making last check possible (true meaning success, false meaning failure).
  • gsub can be also used to iterate over string in callback-style, not only for doing replacement.
  • load is shorter than function(...) end.
  • ... is often shorter than arg[1].

Whole idea hidden behind those tricks:

  1. For each character: either remember if nothing is already it or perform check: if current is different from remembered, fail. Otherwise, reset remembered value and continue.
  2. When done, make sure that there's nothing pending in the buffer (e(a==1)). This is required to fail on strings with odd length.
\$\endgroup\$
1
\$\begingroup\$

C++ (gcc), 156 145 bytes

#include <iostream> int f(){ char a[2]; while(std::cin.get(a, 3)) if(a[0] != a[1]) return 0; return 1; } int main() { std::cout << f(); } 

Try it online!

\$\endgroup\$
2
  • \$\begingroup\$ Welcome to the site! C++ is pretty lenient about whitespace so you can save bytes by removing a bunch of it. \$\endgroup\$ Commented Aug 11, 2019 at 11:58
  • \$\begingroup\$ @SriotchilismO'Zaic Thank you! \$\endgroup\$ Commented Aug 11, 2019 at 17:12

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.