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\$
  • 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.

| improve this answer | |
\$\endgroup\$
  • \$\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\$ – Konrad Borowski 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.

| improve this answer | |
\$\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
| improve this answer | |
\$\endgroup\$
  • \$\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
    }
}
| improve this answer | |
\$\endgroup\$
1
\$\begingroup\$

Python, 7 chars.

b in[a]

Where b and a are strings.

| improve this answer | |
\$\endgroup\$
  • \$\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 $&.

| improve this answer | |
\$\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;}}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Any purpose for noOp? \$\endgroup\$ – Cole Johnson 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

| improve this answer | |
\$\endgroup\$
  • \$\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.

| improve this answer | |
\$\endgroup\$
  • \$\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\$ – Gabriel Mills 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'
| improve this answer | |
\$\endgroup\$
  • \$\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)
| improve this answer | |
\$\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
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ @DaveChen: Thanks, == is now removed. \$\endgroup\$ – Heiko Oberdiek 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.

| improve this answer | |
\$\endgroup\$
  • \$\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\$ – David Herrmann Mar 12 '14 at 17:22
0
\$\begingroup\$

D 30

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

return !reduce!"a|b"(a[]^b[]);
| improve this answer | |
\$\endgroup\$
  • \$\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\$ – ratchet freak 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
| improve this answer | |
\$\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.

| improve this answer | |
\$\endgroup\$
  • \$\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\$ – Heiko Oberdiek Mar 14 '14 at 20:45
0
\$\begingroup\$

Python (7)

Assuming strings are stored in variables a and b:

a<=b<=a
| improve this answer | |
\$\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))
| improve this answer | |
\$\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 >.

| improve this answer | |
\$\endgroup\$
  • \$\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
| improve this answer | |
\$\endgroup\$
  • \$\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.

| improve this answer | |
\$\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.
| improve this answer | |
\$\endgroup\$
  • 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.

| improve this answer | |
\$\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
| improve this answer | |
\$\endgroup\$
  • 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;
}
| improve this answer | |
\$\endgroup\$
  • 1
    \$\begingroup\$ You can drop the parentheses: *a-*b?0:*a?c(++a,++b):1 \$\endgroup\$ – n̴̖̋h̷͉̃a̷̭̿h̸̡̅ẗ̵̨́d̷̰̀ĥ̷̳ 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
    
| improve this answer | |
\$\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

| improve this answer | |
\$\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++]));
}
| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ why not just a.SequenceEqual(b) ??? \$\endgroup\$ – Habib Mar 13 '14 at 16:58
  • \$\begingroup\$ @Habib I'm stupid. :D \$\endgroup\$ – Raz Megrelidze 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)
| improve this answer | |
\$\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.

| improve this answer | |
\$\endgroup\$

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