29
\$\begingroup\$

Your task is simple. Determine if one string equals the other (not address, the value) without the use of equality operators (such as ==, ===, or .equal()) or inequality (!=, !==) anything similar for other languages. This means anywhere! You may not use these operators anywhere in the code. You may however, you use toggles such as !exp as you're not directly comparing the exp != with something else.

In addition, you may not use any functions such as strcmp, strcasecmp, etc.

As for comparison operators (>=, <=, >, <), they are also disallowed. I realize that some answers include this, but I'd really like to see more answers that don't borderline the equality operator.


An example using PHP is shown:

<?php

$a = 'string';
$b = 'string';

$tmp = array_unique(array($a, $b));

return -count($tmp) + 2;

Simply return true or false (or something that evaluates in the language to true or false like 0 or 1) to indicate if the strings match. The strings should be hardcoded seen in the above example. The strings should not be counted in the golf, so if you declare the variable before hand, don't count the declaration.

\$\endgroup\$
11
  • 1
    \$\begingroup\$ Is it necessary to output the result, or simply write a function to return a bool? If writing a complete program is required, that could make-or-break answers in languages with (relatively) significant boilerplate to create a functioning executable like Java and C# (such is the nature of the beast, but this challenge has little in the way of concrete guidelines, leaving much to interpretation/choice). And how are we to take the strings? Hardcoding, reading from STDIN, pass as command-line arguments? \$\endgroup\$
    – Tony Ellis
    Mar 12 '14 at 14:23
  • \$\begingroup\$ Is this [code-golf] or a [popularity-contest]? It can't be both. \$\endgroup\$
    – Gareth
    Mar 12 '14 at 14:23
  • \$\begingroup\$ Sorry, I have modified my questions to reflect both comments. \$\endgroup\$
    – Dave Chen
    Mar 12 '14 at 14:32
  • \$\begingroup\$ So inequality is allowed? \$\endgroup\$
    – user80551
    Mar 12 '14 at 14:41
  • \$\begingroup\$ If the strings are to be hardcoded more than once(each) , do i have to count their length? \$\endgroup\$
    – user80551
    Mar 12 '14 at 15:13

82 Answers 82

1
\$\begingroup\$

C - 86 83

main(int i,char**v){return*v[1]&!(*v[1]++^*v[2]++)?main(3,v):!(*--v[1]^*--v[2]);}

Obvioulsy not the shortest, but this doesn't work with string variables and instead takes the strings as input from the console. Also, I sort of like the recursive main, even if it's obviously not the shortest version. But certainly the least advisable.

\$\endgroup\$
2
  • \$\begingroup\$ You don't need spaces around many operators. For example, char** v can be written as char**v. There are some exceptions (like 42 / *pointer), but in most cases spaces can be safely removed near special characters. \$\endgroup\$ Mar 13 '14 at 18:38
  • \$\begingroup\$ And an apersand too much. Not on top today. \$\endgroup\$
    – SBI
    Mar 13 '14 at 18:46
1
\$\begingroup\$

C++: 104 105 characters

#include<string>
#include<set>
template<typename T>
int f(T a,T b){std::set<T>S={a};return S.count(b);}

EDIT: Saved a character by making it a template function.

Function itself is 51 characters. Other C++ answers already posted are shorter, but I wanted to try one that wasn't also pure C. In fact, this requires C++11. For earlier versions of C++ you can replace std::set<T>S={a}; with std::set<T>S(&a,&a+1); at the expense of an extra 5 characters.

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

Excel VBA

Function stringmatch()
a = ""
b = ""
For i = 1 To Len(a)
If Asc(Right(Left(a, i), 1)) - Asc(Right(Left(b, i), 1)) Or Len(a) - Len(b) Then
debug.print "string unnmatch"
Exit Function
End If
Next
debug.print  "string match"
End Function
\$\endgroup\$
4
  • \$\begingroup\$ I think your <> is classified as an inequality operator, which is not permitted by the rules. \$\endgroup\$
    – user12205
    Mar 13 '14 at 21:43
  • \$\begingroup\$ @Ace oh thx, seeing "=" is allowed I thought "<>" is also allowed \$\endgroup\$
    – Alex
    Mar 13 '14 at 21:49
  • 1
    \$\begingroup\$ = is allowed as an assignment operator. If your language uses this symbol as an equality operator you still cannot use it. (This applies to Visual Basic .NET, I don't know about Excel VBA.) \$\endgroup\$
    – user12205
    Mar 13 '14 at 21:57
  • \$\begingroup\$ Oh ok thanks, I have used another expression (edited code) \$\endgroup\$
    – Alex
    Mar 13 '14 at 22:03
1
\$\begingroup\$

Groovy 347

def compare(str1,str2){
    def str1val = 0
    def str2val = 0

    MessageDigest md5 = MessageDigest.getInstance("MD5")
    md5.digest(str1.getBytes("UTF-8")).each{ str1val += it*2 }
    md5.digest(str2.getBytes("UTF-8")).each{ str2val += it*2 }

    if(!(str1val-str2val)) {
        return true    
    } else {
        return false
    }
}
\$\endgroup\$
1
\$\begingroup\$

Python, 7 chars.

b in[a]

Where b and a are strings.

\$\endgroup\$
1
  • \$\begingroup\$ You can write this b in[a] with one less character. \$\endgroup\$
    – r.e.s.
    Mar 20 '14 at 18:14
1
\$\begingroup\$

Perl - 10

/^\Q$w\E$/

The input is in $_ and $w. The output is stored in $&.

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

Java (235 characters for golfed version at bottom).

Strings are not hardcoded, but this is a trivial change.

   public boolean areEqual(String a, String b) {
    int[] q = new int[1];
    int i = 0;
    try {
        while (true) {
            noOp(q[(int) a.charAt(i) - (int) b.charAt(i)]);
            i++;
        }
    } catch (Error e) {
        try {
            a.charAt(i);
        } catch (Error e2) {
            try {
                b.charAt(i) {catch(Error e3){
                    return true;
                }
                }
            }


            return false;
        }
        return true;
    }
}

public void noOp(int i) {
}

Traverses both strings, using the difference in chars to select an array index (which is 0-based). No in-loop comparisons or Math.max used. Using Error as a throwable instead.

Golfed for use under certain circumstances (instantiated class, used from same package):

boolean a(String a,String b){boolean t=true,f=!t;int[]q={1};int i=0;try{while(t){q[(int)a.charAt(i)-(int)b.charAt(i)];i++;}}catch(Error e){try{a.charAt(i);}catch(Error z){try{b.charAt(i){catch(Error g){return t;}}}return f;}return t;}}
\$\endgroup\$
3
  • \$\begingroup\$ Any purpose for noOp? \$\endgroup\$
    – Cole Tobin
    Mar 13 '14 at 23:24
  • \$\begingroup\$ The golfed and ungolfed code don't compile... \$\endgroup\$
    – Poke
    Mar 26 '17 at 1:47
  • 1
    \$\begingroup\$ @ColeJohnson I'm guessing the noOp function is because array[i] isn't a statement by itself. Rather than calling a function OP could just set the value of that array index since it's not used anyway. \$\endgroup\$
    – Poke
    Mar 26 '17 at 1:48
1
\$\begingroup\$

APL (Dyalog Extended), 4 bytesSBCS

Anonymous tacit infix function. Requires ⎕IO←0

~⍳⍥⍮

Try it online!

⍥⍮ put each argument into a list

 index of right list's elements in left list (0 if match, 1 if not)

~ logical NOT

\$\endgroup\$
5
  • \$\begingroup\$ 5 bytes possible \$\endgroup\$
    – user41805
    Dec 29 '19 at 18:27
  • \$\begingroup\$ @KritixiLithos What was yours? \$\endgroup\$
    – Adám
    Dec 29 '19 at 18:52
  • \$\begingroup\$ 2= in place of -1= \$\endgroup\$
    – user41805
    Dec 29 '19 at 18:57
  • \$\begingroup\$ @KritixiLithos Wouldn't = be forbidden? I had ¯1+. \$\endgroup\$
    – Adám
    Dec 29 '19 at 19:30
  • \$\begingroup\$ Ah, forgot about that \$\endgroup\$
    – user41805
    Dec 30 '19 at 16:12
1
\$\begingroup\$

PowerShell, 30 bytes

param($a,$b)$a-in$b-and$b-in$a

Try it online!

Takes two string inputs as command line parameters, -a and -b.

PowerShell, 20 16 bytes

-4 bytes thanks to @mazzy!

!($args|gu).Rank

Try it online!

Alternate answer, takes two strings as commandline arguments.

\$\endgroup\$
2
  • \$\begingroup\$ nice alternative. you can save more Try it online! \$\endgroup\$
    – mazzy
    Dec 30 '19 at 3:36
  • \$\begingroup\$ @mazzy thanks, I didn't even know the Rank property existed until now! \$\endgroup\$
    – GMills
    Dec 30 '19 at 22:30
0
\$\begingroup\$

Python, 79

a=list(a)
b=list(b)
for i in range(len(a)):
 if ord(a[i])-ord(b[i])<0:
  print 'n'
\$\endgroup\$
4
  • \$\begingroup\$ The question has been edited: the strings should be hard-coded, though I think your approach is better (golfier). \$\endgroup\$
    – 11684
    Mar 12 '14 at 14:37
  • \$\begingroup\$ It will print n multiple times \$\endgroup\$
    – user80551
    Mar 12 '14 at 14:43
  • \$\begingroup\$ At the cost of a few chars, I could make it better \$\endgroup\$
    – TheDoctor
    Mar 12 '14 at 14:47
  • \$\begingroup\$ Your program does not return whether the strings are equal or not, although it could be changed trivially to suit the rules. \$\endgroup\$
    – user10766
    Mar 12 '14 at 16:20
0
\$\begingroup\$

Python - 52 chars without strings (76 with strings)

The in operator might be skirting the edges, but the rules disallow strict equality comparison, not similarity comparison.

a="string"
b="string"
x=a in b and not(len(a)-len(b)>0 or len(a)-len(b)<0)
\$\endgroup\$
0
\$\begingroup\$

Perl, 24 bytes

$r=!(-1+keys{$a,1,$b,1})

The two strings are given in $a and $b. The result is stored in $r.

The trick is using a hash array. If the strings are equal, then only one hash entry is created.


A standalone variant that gets the string from STDIN and returns 0, if the strings match and 1 otherwise:

$h{<>}=$h{<>}=1;exit -1+keys%h
\$\endgroup\$
1
  • \$\begingroup\$ @DaveChen: Thanks, == is now removed. \$\endgroup\$ Mar 12 '14 at 14:57
0
\$\begingroup\$

Ruby, 21

Online version

Strings have to be stored in a and b:

!!(a+b=~/^(#{a})\1$/)

Checks if the concatenation of a and b contains a twice.

\$\endgroup\$
3
  • \$\begingroup\$ Insufficient. Gives true for a="string"; b="stringstring". You have to anchor the regular expression to the start of string too with ^. \$\endgroup\$
    – manatwork
    Mar 12 '14 at 15:37
  • 1
    \$\begingroup\$ I feel like =~ needs to be forbidden, or you can just do !!(a=~/^#{b}$/) \$\endgroup\$
    – histocrat
    Mar 12 '14 at 16:50
  • \$\begingroup\$ Well, it's just an abbreviation for .match(x): !!(a+b).match(/^(#{a})\1$/) - but yes, it somehow is an equality operator... \$\endgroup\$ Mar 12 '14 at 17:22
0
\$\begingroup\$

D 30

string a="somestring";
string b="somestring";

return !reduce!"a|b"(a[]^b[]);
\$\endgroup\$
2
  • \$\begingroup\$ I think !reduce! falls under the banned equality operators. \$\endgroup\$
    – user10766
    Mar 12 '14 at 16:31
  • \$\begingroup\$ it negates the integer result, no different than the C solution using the same xor trick \$\endgroup\$ Mar 12 '14 at 16:32
0
\$\begingroup\$

Python 15 - 2( if you hard code the string in the solution) = 13

>>> s = 'string'
>>> t = 'string'
>>> 1 is len({s,t})
True
>>> s = 'string1'
>>> t = 'string2'
>>> 1 is len({s,t})
False

Python 17

>>> s = 'string'
>>> t = 'string'
>>> s in t and t in s
True
>>> s = 'string1'
>>> t = 'string2'
>>> s in t and t in s
False
\$\endgroup\$
0
\$\begingroup\$

Perl, 25 bytes

$r="$a$b"=~/^(\Q$a\E)\1$/

The input is expected in variables $a and $b. The result is stored in $r. It uses a regular expression to check, whether the concatenation "$a$b" is a duplicate of $a.

\$\endgroup\$
2
  • \$\begingroup\$ Does that answer allow for "regex-special" charaters in either $a or $b? (will it still match properly if $a contains a .? \$\endgroup\$
    – IQAndreas
    Mar 14 '14 at 15:29
  • \$\begingroup\$ @IQAndreas: Yes, the special characters are disabled by \Q...\E. \$\endgroup\$ Mar 14 '14 at 20:45
0
\$\begingroup\$

Python (7)

Assuming strings are stored in variables a and b:

a<=b<=a
\$\endgroup\$
0
\$\begingroup\$

Emacs Lisp

(split-string-and-unquote a b)

returns nil when a == b, something else when a != b

(print (if (split-string-and-unquote a b) "not equal..." "equal!"))

If I'm doing string work in elisp I use the popular package s.el in which it could be written a little shorter and without a negated output

(not (s-split a b t))
\$\endgroup\$
0
\$\begingroup\$

Java - 193

new int[]{0,1,0}[new BigInteger(a.getBytes()).subtract(new BigInteger(b.getBytes())).signum()+1]

No comparison operators at all, not even a < or >.

\$\endgroup\$
1
  • \$\begingroup\$ This is just a code snippet. The consensus for challenges on PPCG is that a full program or function is required unless explicitly stated in the question. Moreover 1 and 0 are not truthy and falsey in java so I'm not sure this is allowed. Finally you're making use of Java's BigInteger but you're not taking the byte count hit for the import of that class. \$\endgroup\$
    – Poke
    Mar 26 '17 at 2:00
0
\$\begingroup\$

C - 45 characters

r;main(){ // 9 chars here
    char *a = "str2";
    char *b = "str1";
while(r+=*a^*b,*a++**b++);return!r;} // 36 more here
\$\endgroup\$
3
  • \$\begingroup\$ Fails if: a="str1"; b="str1b" \$\endgroup\$
    – Emmet
    Mar 13 '14 at 17:49
  • \$\begingroup\$ Works for me. The catch is when run from terminal, "equal" means "failure" (non-zero return code). \$\endgroup\$
    – aragaer
    Mar 13 '14 at 18:02
  • \$\begingroup\$ You're right. My apologies. When I ran it, I was inconsistently thinking of the shell's idea of true/false and C's, which are the opposite way around. \$\endgroup\$
    – Emmet
    Mar 13 '14 at 18:29
0
\$\begingroup\$

C++ 30

#include<string>
std::string a = "test", b = a;
int main(){return!(a<b||a>b);}

I'm not counting the first two lines because:

The strings should not be counted in the golf.

And here are some tests.

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

Delphi (412 83 75)

Can probably be done shorter but was fun to do, going to see if i can get some off.
412 -> 83 Cant believe I missed this... Checks if s1 is in s2 and if s2 is in s1. Saved 329 chars Cheers
83 -> 75 Thanks to Manatwork. Changed check if s1 is in s2 and other way around. Saved 8 characters

const s1='string12';s2='string12';begin Write(Pos(s1,s2)*Pos(s2,s1)>0);end.

Ungolfed

const
  s1='string12';
  s2='string22';
begin
  Write(Pos(s1,s2)*Pos(s2,s1)>0);
end.
\$\endgroup\$
1
  • 1
    \$\begingroup\$ A few tests I made shows that Pos(s1,s2)*Pos(s2,s1)>0 would also do it. \$\endgroup\$
    – manatwork
    Mar 13 '14 at 10:33
0
\$\begingroup\$

Dart - 15

Strings are stored in a en b.

[a].contains(b)

[a] creates a List with a.

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

Python 2 - 50 54 (including strings)

Thanks to Ace for way around the "==" issue

a='string'
b='string'
not(len(''.join(set(a+b)))-len(a))

Output

True

Non-equal strings

a='string'
b='String'
not(len(''.join(set(a+b)))-len(a))

Output

False
\$\endgroup\$
2
  • 2
    \$\begingroup\$ Can't use ==, even if you're not comparing the strings. \$\endgroup\$
    – Dave Chen
    Mar 12 '14 at 15:32
  • \$\begingroup\$ You may wish to use not (len(''.join(set(a+b)))-len(a)) instead. \$\endgroup\$
    – user12205
    Mar 12 '14 at 19:35
0
\$\begingroup\$

C++ - 66 57 53

int c(char*a,char*b){return *a-*b?0:*a?c(++a,++b):1;}

with the ungolfed version:

int mystrcmp( char* a, char* b )
{
  // If the characters don't match, we're done
  if( *a - *b )
  {
      return 0;
  }
  
  // If they do match, and both were nulls, we are done 
  if( !*a )
  {
      return 1;
  }
  
  return mystrcmp( ++a, ++b );
}

Driver program in original post below.


Old version: The golfed version:

int c(char*a, char*b){while(*a|*b)if(*a++-*b++)return 0;return 1;}

Here is a full driver program with comments:

#include <iostream>

using std::cout;
using std::endl;

int mystrcmp( char* a, char* b ) {
   // The comparison will continue as long as both *a and *b are not '\0'.
   // If one of them goes '\0' but the other does not, the strings are not 
   // of equal length and at that point we will return 0.
   while( *a | *b ) {
     // Compare the current character and return 0 if they are not equal.
     // *a++ will return the value of *a and then increment the pointer -
     // see http://stackoverflow.com/questions/9255147/does-p-increment-after-dereferencing
     if(*a++ - *b++) {
       return 0;
     }
   }

   // If we got here, both strings are equal up to and including the last '\0'.
   return 1;
}

int main()
{   
   // Prints 1
   cout << mystrcmp("Hello.", "Hello.") << endl;

   // Prints 1       
   cout << mystrcmp("Hello, world!", "Hello, world!") << endl;
   
   // Prints 0
   cout << mystrcmp("Hello", "Hello.") << endl;

   // Prints 0       
   cout << mystrcmp("Hello.", "Zello.") << endl;
   
   // Prints 0
   cout << mystrcmp("Hello", "Hallo") << endl;
   
   // Prints 0
   cout << "Hello World" << endl; 
   
   return 0;
}
\$\endgroup\$
2
  • 1
    \$\begingroup\$ You can drop the parentheses: *a-*b?0:*a?c(++a,++b):1 \$\endgroup\$ Mar 13 '14 at 10:59
  • \$\begingroup\$ Thanks @n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳, for some reason I thought there would a problem with the precedence. \$\endgroup\$
    – CompuChip
    Mar 13 '14 at 14:40
0
\$\begingroup\$

C#

I know there's already a C# answer, I just wanted to show other options. :)

boolean:

  • 51

    !Convert.ToBoolean(new[]{a,b}.Distinct().Count()-1)
    

1 or 0:

  • 32

    -new[]{a,b}.Distinct().Count()+2
    
\$\endgroup\$
0
\$\begingroup\$

Q - [3 bytes]

a:"string"
b:"string"

a~b

I think this is a valid answer as ~ isn't an equals operator. From a Q tutorial:

~ asks whether two entities have the same contents.

http://kx.com/q/d/primer.htm

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

C#

void Main()
{
    Console.WriteLine(StringEqual("pie","pie")); // true
}

bool Equals(int a,int b)
{
    var aBytes = BitConverter.GetBytes(a);
    var bBytes = BitConverter.GetBytes(b);

    return aBytes.SequenceEqual(bBytes);
}

bool StringEqual(string a,string b)
{
    int i = 0;
    return a.All((c) => Equals((int)c,(int)b[i++]));
}
\$\endgroup\$
2
  • \$\begingroup\$ why not just a.SequenceEqual(b) ??? \$\endgroup\$
    – Habib
    Mar 13 '14 at 16:58
  • \$\begingroup\$ @Habib I'm stupid. :D \$\endgroup\$ Mar 13 '14 at 17:18
0
\$\begingroup\$

Javascrpt: 38 chars (without a-b declarations) || 31 without alert()

a="string";
b="string";

o={};o[a]=0;alert(o.hasOwnProperty(b))

sets an object key named the value of a -- checks for a key named the value of b in that object.

without alert:

o={};o[a]=0;o.hasOwnProperty(b)
\$\endgroup\$
0
\$\begingroup\$

J - 6 char

A J expression which tests for string equality without testing for string equality? Here's one:

e./a;b        NB. is a boxed in b boxed?

Not good enough? Want some more options? Go ahead, have some more, J has plenty.

<:#~.a;b      NB. (the number of the unique items among the two) - 1
1-{:~:a;b     NB. 1 - (whether the second item is unique, given the first)
2-#]/.~a;b    NB. 2 - (the number of piles the strings will sort themselves into)
+/(/:*\:)a;b  NB. is sorting them forwards the same as sorting them backwards?
A.|./:\:~a;b  NB. will sorting them forwards after sorting them backwards do anything?

The common subexpression here, a;b, is a linked to b. It puts a and b into boxes before appending them into a list. This is J's closest approximation to non-rectangular arrays: if you just tried to put the two strings in a 2-item list, the shorter would be padded with spaces on the right, which could result in you comparing 'a' and 'a ' as equal.

\$\endgroup\$

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