20
\$\begingroup\$

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
\$\endgroup\$
7
  • 3
    \$\begingroup\$ I suggest a test case of f("_test", "test"). \$\endgroup\$
    – Doorknob
    Jul 28, 2017 at 2:51
  • \$\begingroup\$ @Doorknob Added. \$\endgroup\$ Jul 28, 2017 at 3:14
  • 1
    \$\begingroup\$ I suggest adding f("test", "tset"), as I think one answer gives an unexpected result for it. \$\endgroup\$ Jul 29, 2017 at 0:11
  • \$\begingroup\$ @ØrjanJohansen Done. \$\endgroup\$ Jul 29, 2017 at 18:36
  • \$\begingroup\$ 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 >? \$\endgroup\$
    – aschepler
    Jul 29, 2017 at 21:54

29 Answers 29

8
\$\begingroup\$

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

\$\endgroup\$
1
  • 1
    \$\begingroup\$ /-|_/g saves a byte \$\endgroup\$ Jul 28, 2017 at 13:06
6
\$\begingroup\$

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

\$\endgroup\$
10
  • \$\begingroup\$ -1 byte. \$\endgroup\$
    – notjagan
    Jul 28, 2017 at 2:23
  • \$\begingroup\$ @notjagan Neat trick; thanks! \$\endgroup\$
    – hyper-neutrino
    Jul 28, 2017 at 2:26
  • \$\begingroup\$ @notjagan I did not know you could do that, but I guess it makes sense, cool \$\endgroup\$
    – Stephen
    Jul 28, 2017 at 2:27
  • \$\begingroup\$ -14 bytes! \$\endgroup\$
    – notjagan
    Jul 28, 2017 at 3:31
  • 1
    \$\begingroup\$ even shorter \$\endgroup\$
    – Wheat Wizard
    Jul 28, 2017 at 5:57
4
\$\begingroup\$

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?
\$\endgroup\$
0
4
\$\begingroup\$

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

\$\endgroup\$
1
  • \$\begingroup\$ 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). \$\endgroup\$
    – Adalynn
    Jul 29, 2017 at 15:05
3
\$\begingroup\$

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
\$\endgroup\$
3
\$\begingroup\$

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.

\$\endgroup\$
4
  • \$\begingroup\$ Oh yeah lol, I still need to fix that. You can save a byte by using „-_SK instead of '-K'_K. \$\endgroup\$
    – Adnan
    Jul 28, 2017 at 11:19
  • \$\begingroup\$ @Adnan And I knew there was a way. Thanks! \$\endgroup\$ Jul 28, 2017 at 12:59
  • \$\begingroup\$ 11 bytes if you change SK to м. \$\endgroup\$ May 11, 2018 at 9:46
  • \$\begingroup\$ @KevinCruijssen Hm, I'll update this answer. I don't think м existed back then. :P \$\endgroup\$ May 11, 2018 at 11:03
3
\$\begingroup\$

Jelly, 11 bytes

ḟ⁾-_Œl,Ḣµ€E

Try it online!

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

\$\endgroup\$
4
  • \$\begingroup\$ Take a list of two strings like ["symbolsAre_too>_>", "symbols_areTOO>>"] and use Ḣ;ḟ⁾-_Œl$µ€E instead for -2. Beat that Pyth! \$\endgroup\$ Jul 28, 2017 at 9:33
  • \$\begingroup\$ ...or even just ḟ⁾-_Œl,Ḣµ€E for 11 bytes. \$\endgroup\$ Jul 28, 2017 at 14:29
  • \$\begingroup\$ No problem, maybe credit Erik for 2 and me for 1 :) \$\endgroup\$ Jul 28, 2017 at 22:37
  • \$\begingroup\$ @JonathanAllan Ah. Good idea; I'll do that :) \$\endgroup\$
    – hyper-neutrino
    Jul 28, 2017 at 22:39
3
\$\begingroup\$

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.

\$\endgroup\$
3
  • \$\begingroup\$ Not a guru, but I got inspired to check out the String method list. .delete("_-") is shorter. \$\endgroup\$ Jul 28, 2017 at 6:50
  • \$\begingroup\$ f[x] is always a valid substitution for f.call(x) when stabby lambdas are involved. \$\endgroup\$
    – Value Ink
    Jul 28, 2017 at 23:41
  • \$\begingroup\$ @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. \$\endgroup\$
    – Wheat Wizard
    Jul 29, 2017 at 0:58
2
\$\begingroup\$

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)
}
\$\endgroup\$
2
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ all(/=a)"-_". Also after your latest edit, f needs to become an operator. \$\endgroup\$ Jul 28, 2017 at 5:41
  • \$\begingroup\$ @ØrjanJohansen Ah thanks. I thought there was a shorter way to do notElem but I couldn't remember it for the life of me. \$\endgroup\$
    – Wheat Wizard
    Jul 28, 2017 at 5:43
2
\$\begingroup\$

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.

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

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.

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

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 ω-"-_.

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

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.

\$\endgroup\$
5
  • \$\begingroup\$ 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? \$\endgroup\$ Jul 29, 2017 at 0:10
  • \$\begingroup\$ @ØrjanJohansen Good point... it'll fail for that case. As for the link, I've tested it and it works fine. \$\endgroup\$ Jul 29, 2017 at 0:26
  • \$\begingroup\$ 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! \$\endgroup\$ Jul 29, 2017 at 0:27
  • \$\begingroup\$ @Ø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. \$\endgroup\$ Jul 29, 2017 at 0:39
  • \$\begingroup\$ cough still using Internet Explorer. \$\endgroup\$ Jul 29, 2017 at 0:47
2
\$\begingroup\$

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)

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

Vyxal 3, 10 bytes

…≈¿ᶴ-_½-ʀ≈

Try it Online!

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

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!

\$\endgroup\$
2
  • 2
    \$\begingroup\$ -6 bytes. \$\endgroup\$
    – notjagan
    Jul 28, 2017 at 3:28
  • \$\begingroup\$ Of course, set, I forgot its existence!! Thanks a lot!! \$\endgroup\$
    – 0xffcourse
    Jul 28, 2017 at 4:01
1
\$\begingroup\$

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
\$\endgroup\$
0
1
\$\begingroup\$

Retina, 28 bytes

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

Try it online!

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

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 ().

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

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.

\$\endgroup\$
2
  • \$\begingroup\$ if you use a local function for string.Concat(...) you can save 2 bytes ;) \$\endgroup\$
    – kusi581
    Jul 28, 2017 at 10:49
  • 1
    \$\begingroup\$ @kusi581 Thanks, saved 12 bytes. \$\endgroup\$ Jul 28, 2017 at 10:53
1
\$\begingroup\$

Java (OpenJDK 8), 95 bytes

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

Try it online! Pretty straight forward.

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

Pyke, 13 bytes

F'hl1"-_"-)Xq

Try it online!

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

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')
}
\$\endgroup\$
4
  • \$\begingroup\$ 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^. \$\endgroup\$ Jul 29, 2017 at 3:54
  • \$\begingroup\$ @ØrjanJohansen I thought we could assume the inputs were both valid identifiers. But then that example with > was added, hmm. \$\endgroup\$
    – aschepler
    Jul 29, 2017 at 22:00
  • \$\begingroup\$ 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... \$\endgroup\$ Jul 29, 2017 at 23:05
  • \$\begingroup\$ @ØrjanJohansen Yeah, I noticed - isn't in the grammar description of identifier - but then other parts of that document imply it is allowed. \$\endgroup\$
    – aschepler
    Jul 29, 2017 at 23:24
1
\$\begingroup\$

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
\$\endgroup\$
4
  • \$\begingroup\$ I think you can do ⊃⍺=⍵ instead instead of ⍺[1]=⍵[1] \$\endgroup\$
    – user41805
    Jul 29, 2017 at 14:33
  • \$\begingroup\$ No, because the arguments could be of a different length! \$\endgroup\$
    – Adalynn
    Jul 29, 2017 at 14:38
  • 1
    \$\begingroup\$ In that case, ⊃⍵ instead of ⍵[1] should work \$\endgroup\$
    – user41805
    Jul 29, 2017 at 14:38
  • 1
    \$\begingroup\$ Maybe even ⊃⍺=⊃⍵ instead of ⍺[1]=⍵[1] \$\endgroup\$
    – user41805
    Jul 29, 2017 at 14:41
1
\$\begingroup\$

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)))))
\$\endgroup\$
1
\$\begingroup\$

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 "_-".
\$\endgroup\$
0
\$\begingroup\$

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.
\$\endgroup\$
0
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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