Are these identifiers equivalent?

20

3

In the language Nim, the rules for differentiating identifiers are slightly more relaxed than most other languages. Two identifiers are equivalent or address the same variable if they follow these rules:

  • the first character of both are the same (case sensitive)
  • both strings are the same (case insensitive) after removing all instances of the characters - and _

Challenge

Write a program/function that takes two strings that represent Nim identifiers and output a truthy or falsey value based on whether or not they are equivalent by the rules above.

Specifications

  • Standard I/O rules apply.
  • Standard loopholes are forbidden.
  • The strings will only contain ASCII printables. You do not need to check if it's a valid identifier.
  • The strings may be taken as two separate inputs, list of strings, etc. (you know the drill)
  • Empty strings need not be handled.
  • The output must be consistent for both truthy and falsey values.
  • This challenge is not about finding the shortest approach in all languages, rather, it is about finding the shortest approach in each language.
  • Your code will be scored in bytes, usually in the encoding UTF-8, unless specified otherwise.
  • Built-in functions that perform this task are allowed but including a solution that doesn't rely on a built-in is encouraged.
  • Explanations, even for "practical" languages, are encouraged.

Test cases

Input                                    Output

count, Count                             falsey
lookMaNoSeparator, answer                falsey
_test, test                              falsey
test, tset                               falsey
aVariableName, a_variable_name           truthy
numbers_are_cool123, numbersAreCool123   truthy
symbolsAre_too>_>, symbols_areTOO>>      truthy

Ungolfed reference implementation

This is written in Nim, itself.

import strutils, re

proc sameIdentifier(a, b: string): bool =
  a[0] == b[0] and
    a.replace(re"_|–", "").toLower == b.replace(re"_|–", "").toLower

totallyhuman

Posted 2017-07-28T01:53:11.083

Reputation: 15 378

3I suggest a test case of f("_test", "test"). – Doorknob – 2017-07-28T02:51:34.817

@Doorknob Added. – totallyhuman – 2017-07-28T03:14:19.470

1I suggest adding f("test", "tset"), as I think one answer gives an unexpected result for it. – Ørjan Johansen – 2017-07-29T00:11:31.527

@ØrjanJohansen Done. – totallyhuman – 2017-07-29T18:36:22.640

Wait, so input is strings that "represent Nim identifiers", and we "do not need to check if it's a valid identifier", but then one of the examples contains >? – aschepler – 2017-07-29T21:54:23.567

It looks like if we can assume actual Nim identifiers, even - is disallowed. – Ørjan Johansen – 2017-07-29T23:06:20.210

To be honest, I don't know Nim much. To be fair, I didn't say they were valid Nim identifiers. :P However much they might be wrong, the challenge is still the same. Nim is just an inspiration. ;) – totallyhuman – 2017-07-30T00:21:41.147

Answers

7

JavaScript (ES6), 62 61 bytes

Saved 1 byte thanks to @JohanKarlsson

Takes input in currying syntax (a)(b). Returns a boolean.

a=>b=>(r=s=>s[0]+s.replace(/-|_/g,'').toUpperCase())(b)==r(a)

Test cases

let f =

a=>b=>(r=s=>s[0]+s.replace(/-|_/g,'').toUpperCase())(b)==r(a)

console.log(f("count")("Count"))                           // falsey
console.log(f("lookMaNoSeparator")("answer"))              // falsey
console.log(f("_test")("test"))                            // falsey
console.log(f("aVariableName")("a_variable_name"))         // truthy
console.log(f("numbers_are_cool123")("numbersAreCool123")) // truthy

Arnauld

Posted 2017-07-28T01:53:11.083

Reputation: 111 334

1/-|_/g saves a byte – Johan Karlsson – 2017-07-28T13:06:09.227

6

Python 3, 76 bytes

lambda a,b:f(*a)==f(*b)
f=lambda f,*r:[f+k.lower()for k in r if~-(k in'-_')]

Try it online!

-1 byte thanks to notjagan
-3 bytes thanks to Wheat Wizard

HyperNeutrino

Posted 2017-07-28T01:53:11.083

Reputation: 26 575

-1 byte. – notjagan – 2017-07-28T02:23:00.807

@notjagan Neat trick; thanks! – HyperNeutrino – 2017-07-28T02:26:54.247

@notjagan I did not know you could do that, but I guess it makes sense, cool – Stephen – 2017-07-28T02:27:56.283

-14 bytes! – notjagan – 2017-07-28T03:31:20.753

@notjagan That only checks if the sets of characters are equal, not the strings themselves. – xnor – 2017-07-28T03:56:02.910

@xnor I overlooked the fact that this requires order preservation. I guess -6 bytes will have to suffice.

– notjagan – 2017-07-28T03:59:40.633

You may need str.isalnum() – tsh – 2017-07-28T04:54:15.970

slightly shorter – Post Rock Garf Hunter – 2017-07-28T05:50:01.613

1even shorter – Post Rock Garf Hunter – 2017-07-28T05:57:12.037

@WheatWizard Thanks! – HyperNeutrino – 2017-07-28T19:23:09.920

4

Actually, 15 bytes

⌠p"-_"(-Σùo⌡M═Y

Try it online!

Fun fact: this works with any number of inputs (it always returns truthy for less than 2 inputs).

Explanation:

⌠p"-_"(-Σùo⌡M═Y
⌠p"-_"(-Σùo⌡M    for each input:
 p                 separate the first character
  "-_"(-           remove all dashes and underscores from the rest of the string
        Σù         concatenate the list from the last operation and lowercase the string
          o        append it to the first character
             ═Y  are none of the elements unique?

Mego

Posted 2017-07-28T01:53:11.083

Reputation: 32 998

3

Jelly, 11 bytes

ḟ⁾-_Œl,Ḣµ€E

Try it online!

-2 bytes thanks to Erik the Outgolfer
-1 byte thanks to Jonathan Allan

HyperNeutrino

Posted 2017-07-28T01:53:11.083

Reputation: 26 575

Take a list of two strings like ["symbolsAre_too>_>", "symbols_areTOO>>"] and use Ḣ;ḟ⁾-_Œl$µ€E instead for -2. Beat that Pyth! – Erik the Outgolfer – 2017-07-28T09:33:52.577

...or even just ḟ⁾-_Œl,Ḣµ€E for 11 bytes. – Jonathan Allan – 2017-07-28T14:29:53.737

No problem, maybe credit Erik for 2 and me for 1 :) – Jonathan Allan – 2017-07-28T22:37:15.490

@JonathanAllan Ah. Good idea; I'll do that :) – HyperNeutrino – 2017-07-28T22:39:41.707

3

Pyth, 13 bytes

qFm[hd-r0d"-_

Try it online!

Explanation

qFm[hd-r0d"-_
  m              For each value in the input (which is a list of two strings):
   [             Create a list consisting of
    hd               the first character of each value
      -r0d"-_        and the lowercase version of the value without "-" or "_"
qF               Fold over equivalence; checks to see if both lists are the same

notjagan

Posted 2017-07-28T01:53:11.083

Reputation: 4 011

3

Ruby, 86 64 63 61 51 bytes

f=->x{x[0]+x.upcase.delete("-_")}
->x,y{f[x]==f[y]}

Try it online!

This feels really long still feels a bit long. I would appreciate the help of any Ruby gurus out there in making this at least a bit shorter.

Post Rock Garf Hunter

Posted 2017-07-28T01:53:11.083

Reputation: 55 382

Not a guru, but I got inspired to check out the String method list. .delete("_-") is shorter.

– Ørjan Johansen – 2017-07-28T06:50:34.243

f[x] is always a valid substitution for f.call(x) when stabby lambdas are involved. – Value Ink – 2017-07-28T23:41:40.860

@ValueInk Thanks! I've been trying to figure out how to golf in Ruby based on Stack Overflow answers, so I didn't know that was an option. – Post Rock Garf Hunter – 2017-07-29T00:58:06.410

3

05AB1E, 12 bytes

εćs„-_SKl«}Ë

Try it online!

-1 thanks to Adnan.

Theoretically, εćs„-_-«}Ë should've worked for 10 bytes, but unfortunately this behavior is deprecated for now.

Erik the Outgolfer

Posted 2017-07-28T01:53:11.083

Reputation: 38 134

Oh yeah lol, I still need to fix that. You can save a byte by using „-_SK instead of '-K'_K. – Adnan – 2017-07-28T11:19:53.933

@Adnan And I knew there was a way. Thanks! – Erik the Outgolfer – 2017-07-28T12:59:46.450

11 bytes if you change SK to м. – Kevin Cruijssen – 2018-05-11T09:46:36.667

@KevinCruijssen Hm, I'll update this answer. I don't think м existed back then. :P – Erik the Outgolfer – 2018-05-11T11:03:13.727

3

C++, 288 248 bytes

-5 bytes thanks to Zacharý

#include<string>
#include<algorithm>
#define E(a,v)a.erase(std::remove(a.begin(),a.end(),v),a.end());
#define F(a)for(auto&c:a)c=toupper(c);
int e(std::string&a,std::string&b){if(a[0]!=b[0])return 0;E(a,45)E(b,45)E(a,95)E(b,95)F(a)F(b)return a==b;}

Thanks you, Preprocessor. Also, this code takes advantage of the fact that in C++ the rule to cast int to bool is int_var!=0

HatsuPointerKun

Posted 2017-07-28T01:53:11.083

Reputation: 1 891

Add a ; after the definition of F. Then, change the first return statement to return 0;E(a,45)E(b,45)E(a,95)E(b,95)F(a)F(b). – Zacharý – 2017-07-29T15:05:52.203

2

CJam, 20 bytes

{_"-_"f-:el:=\:c:=*}

Takes input in the form of ["string1","string2"].

Try it Online (testing version)

{
_      e# make copy of input
"-_"f- e# remove all "-" and "_" from both words in copy
:el    e# convert words in copy to lowercase
:=     e# 1 if both words in copy are equal, 0 if not
\      e# move original version of input to top of stack
:c     e# convert each word in original input to only 1st character
:=     e# 1 if both characters from original input are equal, 0 if not
*      e# multply the two numbers we obtained. If and only if both are 1 (true) we return 1 (true)
}

geokavel

Posted 2017-07-28T01:53:11.083

Reputation: 6 352

2

Haskell, 85 78 76 71 68 bytes

2 bytes saved thanks to Ørjan Johansen

import Data.Char
s(a:x)=a:[toLower a|a<-x,all(/=a)"-_"]
x!y=s x==s y

Try it online!

Errors on the empty string.

Post Rock Garf Hunter

Posted 2017-07-28T01:53:11.083

Reputation: 55 382

all(/=a)"-_". Also after your latest edit, f needs to become an operator. – Ørjan Johansen – 2017-07-28T05:41:30.380

@ØrjanJohansen Ah thanks. I thought there was a shorter way to do notElem but I couldn't remember it for the life of me. – Post Rock Garf Hunter – 2017-07-28T05:43:33.080

2

Python 2, 72 bytes

lambda x,y:r(x)==r(y)
r=lambda x:x[0]+x[1:].lower().translate(None,"-_")

Try it online!

Won't work with Python 3 because of the new translate syntax.

jferard

Posted 2017-07-28T01:53:11.083

Reputation: 1 764

2

Excel, 105 bytes

=AND(CODE(A1)=CODE(B1),SUBSTITUTE(SUBSTITUTE(A1,"_",""),"-","")=SUBSTITUTE(SUBSTITUTE(B1,"_",""),"-",""))

CODE() returns numeric code of first character.

String comparison in Excel is case insensitive.

Wernisch

Posted 2017-07-28T01:53:11.083

Reputation: 2 534

2

Husk, 13 bytes

¤=§,←(m_ω-"-_

Try it online!

Builds for each string a pair consisting of the first character of the string and the whole string lowercased and with all occurrences of -/_ removed. Then checks if the two pairs are equal.

A particularity is that - in Husk is set difference (i.e. it removes only the first occurrence found): in order to remove all occurrences, the fixed point of -"-_ is found with ω-"-_.

Leo

Posted 2017-07-28T01:53:11.083

Reputation: 8 482

2

Japt, 14 25 bytes

g ¥Vg ©Uu k"_-" ¥Vu k"_-"

Checks case-insensitive string equality by removing all characters in word 2 from word 1, and removing the -_ characters; that results in an empty string ("") if the words are equal.
Thanks Ørjan Johansen for pointing out the problem with this.

Checks first-char equality and if the uppercased inputs are equal after removing _-.

Try it online!

Explanation

Implicit input: U and V are input strings

g ¥Vg

Check if first letter of U (implicit) equals (¥) the first char of V.

©Uu k"_-" ¥Vu k"_-"

And (©) check if U, uppercased (u) and with _- removed (k), equals (¥) the same for V. Implicitly return the boolean result.

Justin Mariner

Posted 2017-07-28T01:53:11.083

Reputation: 4 746

I cannot get the link to work, but that explanation sounds like it does the wrong thing. What does it give for test vs. tset? – Ørjan Johansen – 2017-07-29T00:10:26.030

@ØrjanJohansen Good point... it'll fail for that case. As for the link, I've tested it and it works fine. – Justin Mariner – 2017-07-29T00:26:13.650

Yeah the link is my own fault - one of these days I need to change to a modern browser. I had better luck with Try it online!

– Ørjan Johansen – 2017-07-29T00:27:58.800

@ØrjanJohansen Could I ask what browser you're using? I'm in the process of improving that CodePen and would like to make it as compatible as TIO. – Justin Mariner – 2017-07-29T00:39:50.790

cough still using Internet Explorer. – Ørjan Johansen – 2017-07-29T00:47:12.077

1

Perl 5, 67 bytes

s/.//,push@a,$&,y/_-//dr for<>;say($a[0]eq$a[2]&&lc$a[3]eq lc$a[1])

Try it online!

Takes the identifiers as input on separate lines.

Explanation:

s/.//,             # remove the first character
push@a,            # storage space, even positions are first character
                   # odd positions are remainder
$&,                # implicit variable holding last matched pattern (first char)
y/_-//dr           # Remove _ and - from remainder of input
for<>;             # iterate over all input lines
say                # output
($a[0]eq$a[2]&&    # check that first character is identical and
lc$a[3]eq lc$a[1]) # so is the lowercase version of the rest

Xcali

Posted 2017-07-28T01:53:11.083

Reputation: 7 671

1

Python 2, 79 73 bytes

-6 bytes thanks to @notjagan: check the length of set of all reduced names is 1 or not.

lambda*l:len({x[0]+re.sub('-|_','',x[1:].lower())for x in l})<2
import re

Try it online!

officialaimm

Posted 2017-07-28T01:53:11.083

Reputation: 2 739

2-6 bytes. – notjagan – 2017-07-28T03:28:33.793

Of course, set, I forgot its existence!! Thanks a lot!! – officialaimm – 2017-07-28T04:01:36.450

1

Retina, 28 bytes

T`L\_-`l_`(?<=.).+
^(.*)¶\1$

Try it online!

Neil

Posted 2017-07-28T01:53:11.083

Reputation: 95 035

1

Charcoal, 29 bytes

∧⁼§θ⁰§η⁰⁼↧⪫⪪⪫⪪θ_ω-ω↧⪫⪪⪫⪪η_ω-ω

Try it online!

This prints a - for truthy and nothing for falsey.

Link to the verbose version. It first compares the first character of both input strings (⁼§θ⁰§η⁰) and then compares the rest of both strings after removing the underscores and the hyphens (⪫⪪⪫⪪θ_ω-ω) and converting to lowercase ().

Charlie

Posted 2017-07-28T01:53:11.083

Reputation: 11 448

1

C#, 101 89 bytes

string g(string s)=>string.Concat(s.ToUpper().Split('-','_'));f=>s=>f[0]==s[0]&g(f)==g(s)

Saved 12 bytes thanks to @kusi581.

TheLethalCoder

Posted 2017-07-28T01:53:11.083

Reputation: 6 930

if you use a local function for string.Concat(...) you can save 2 bytes ;) – kusi581 – 2017-07-28T10:49:51.737

1@kusi581 Thanks, saved 12 bytes. – TheLethalCoder – 2017-07-28T10:53:56.247

1

Java (OpenJDK 8), 95 bytes

a->b->a.charAt(0)==b.charAt(0)&&a.replaceAll("_|-","").equalsIgnoreCase(b.replaceAll("_|-",""))

Try it online! Pretty straight forward.

Roman Gräf

Posted 2017-07-28T01:53:11.083

Reputation: 2 915

1

Pyke, 13 bytes

F'hl1"-_"-)Xq

Try it online!

F         )   -  for i in input():
 'hl1         -   i[0], i.lower()
     "-_"-    -         ^.remove("-_")
           Xq - equal(^)

Blue

Posted 2017-07-28T01:53:11.083

Reputation: 26 661

1

C (gcc), 126 114 bytes

#define p(s)do++s;while(*s==45||*s==95);*s>95?*s-=32:0;
f(char*a,char*b){while(*a&&*a==*b){p(a)p(b)}return*a==*b;}

Try it online!

With whitespace and comments:

#define p(s)                   // Define helper macro p           \
    do ++s;                    // Increment pointer at least once \
    while (*s==45 | *s==95);   // and past any '-' or '_'         \
    *s>95 ? *s -= 32 : 0;      // If lowercase letter, convert to upper

f(char* a, char* b) {          // Define main function f
    while (*a && *a == *b) {   // Loop until end of either string
                               // or a difference found
        p(a)                   // Transform pointer and one char
        p(b)                   // via helper p above
    }
    return *a==*b;             // Test chars equal (on success, both '\0')
}

aschepler

Posted 2017-07-28T01:53:11.083

Reputation: 717

The question specifies ASCII printables, so (1) The first while test can be shortened to *s%50==45. (2) However, the lowercasing is wrong, e.g. it fails on t~ vs. t^. – Ørjan Johansen – 2017-07-29T03:54:26.603

@ØrjanJohansen I thought we could assume the inputs were both valid identifiers. But then that example with > was added, hmm. – aschepler – 2017-07-29T22:00:12.410

Huh. I was going by that example too. Looking now in the Nim manual, even - isn't actually allowed, but the algorithm still includes it...

– Ørjan Johansen – 2017-07-29T23:05:10.500

@ØrjanJohansen Yeah, I noticed - isn't in the grammar description of identifier - but then other parts of that document imply it is allowed. – aschepler – 2017-07-29T23:24:50.460

1

Dyalog APL, 47 32 28 27 26 22 bytes

-4 bytes thanks to Kritixi Lithos

{(=/⊃¨⍵)∧≡/819⌶⍵~'-_'}   

Takes input as a list of the strings.

Try it online!

How?

{(=/⊃¨⍵)∧≡/819⌶⍵~'-_'}
               ⍵~'-_'   Remove '-' and '_'
           819⌶         Lowercase
         ≡/             Equality between elements
        ∧               And
 (=/⊃¨⍵)                The first element of each element is equal

Zacharý

Posted 2017-07-28T01:53:11.083

Reputation: 5 710

I think you can do ⊃⍺=⍵ instead instead of ⍺[1]=⍵[1] – user41805 – 2017-07-29T14:33:55.843

No, because the arguments could be of a different length! – Zacharý – 2017-07-29T14:38:17.583

1In that case, ⊃⍵ instead of ⍵[1] should work – user41805 – 2017-07-29T14:38:53.340

1Maybe even ⊃⍺=⊃⍵ instead of ⍺[1]=⍵[1] – user41805 – 2017-07-29T14:41:46.503

1

Common Lisp, 98 bytes

(lambda(x y)(and(eql(elt x 0)(elt y 0))(string-equal(#1=remove #\-(#1##\_ y))(#1##\-(#1##\_ x)))))

Try it online!

Ungolfed (super straightforward!) version:

(defun f(x y)
  (and (eql (elt x 0) (elt y 0))         ; check if initial characters are identical
       (string-equal                     ; string comparison (case insensitive)
         (remove #\- (remove #\_ y))     ; remove from both strings the unwanted chars
         (remove #\- (remove #\_ x)))))

Renzo

Posted 2017-07-28T01:53:11.083

Reputation: 2 260

1

R, 76 bytes

function(l)(g=substr(l,1,1))[1]==g[2]&(h=tolower(gsub('-|_','',l)))[1]==h[2]

Anonymous function that takes input as a list of two strings. Takes advantage of the fact that R's string operations, while quite long in # of characters, are vectorized. Additionally wrapping an assignment in parentheses will bind the variable, so (g=substr(l,1,1)) retains a variable to be reused later in the line and similarly for h.

R returns the last evaluated expression as function output.

Ungolfed:

function(l){
  g <- substr(l,1,1)
  h <- tolower(gsub("_|-","",l))
  (g[1]==g[2])&(h[1]==h[2])
}

Try it online! (all test cases)

Giuseppe

Posted 2017-07-28T01:53:11.083

Reputation: 21 077

1

Brachylog, 17 bytes

hᵛ&{{¬∈"_-"&ụ}ˢ}ᵛ

Try it online!

Outputs through predicate success/failure.

h                    The first element
 ᵛ                   is the same for each element of the input,
  &                  and
   {           }ᵛ    for each element of the input the following are the same:
    {      &ụ}ˢ      every element uppercased which satisfies the condition that
     ¬∈              it is not an element of
       "_-"          the string "_-".

Unrelated String

Posted 2017-07-28T01:53:11.083

Reputation: 5 300

0

Erlang 113 bytes

A=fun(L)->string:to_lower(lists:flatten(string:tokens(L,"-_")))end,fun([C|D],[C|E])->A(D)==A(E);(_,_)->a==b end.

a pair of anonymous functions that compare the two lists. meant to be pasted in the erlang shell.

more readable:

A=fun(L) ->
    string:to_lower( % case insensitive
        lists:flatten( % squash all characters back into one list
            string:tokens(L,"-_") % return a list of list of characters
        )
    )
end.
fun([C|D],[C|E]) -> % are the first characters exactly the same?
    A(D)==A(E); % does the rest compare correctly?
   (_,_) -> % first chars not the same
    a==b % shorter than 'false'
end.

JoshRagem

Posted 2017-07-28T01:53:11.083

Reputation: 189

0

Clip, 25 bytes

&=(x(y=AxAy[Aa--m.L`a'-'_

Explanation:

x, y and z may be referenced in a Clip program to implicitly take up to three inputs. Since this program only references x and y, it takes two inputs which are assigned to x and y.

 =(x(y                    First characters of x and y are equal
&                         And
      =AxAy               A(x) == A(y)
           [Aa            Function A, takes parameter a
                m.L`a     Map all elements of a to lower case
              --     '-'_ Remove all occurrences of '-' and '_'

Takes two strings from standard input, outputs 1 and 0 for true and false respectively.

bcsb1001

Posted 2017-07-28T01:53:11.083

Reputation: 450