Introduction
In Android Studio and other IDEs there are code completions to assist efficient code insertion (especially when the names of the classes or methods are so verbose), like the one in the image below.
There are slightly different logics used between IDEs to determine what classes, methods and variables to suggest, but otherwise are common: typing the initial letters of each word, and the identifier matching those initial letters will be suggested.
Challenge
In this challenge, write a program or function which receives two strings, namely input and identifier, determine whether the identifier matches the input.
We split identifier into words where:
- a lowercase letter is followed by an uppercase letter (
"SplitHere" -> "Split", "Here"), - an uppercase letter is followed by an uppercase letter and a lowercase letter (
"SPLITHere" -> "SPLIT", "Here"), or - there is a number or an underscore
_("SPLIT_HERE" -> "SPLIT", "HERE").
If this is still not clear enough, here is the regex representing the condition to split: (?<=[a-z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|[_0-9]. Here are a few samples:
theWord_Example, in which 3 words (the,Word,Example) can be found.THEWORD2EXAMPLE, in which only 2 words (THEWORD,EXAMPLE) can be found (becauseTHEWORDis a run of uppercase letters and so doesEXAMPLE).THEWordEXAMPLE3, in which 3 words (THE,Word,Example) can be found (Wordis considered to be a separate word here).THEWORDEXAMPLEFOUR, in which only 1 words (THEWORDEXAMPLEFOUR) can be found (the whole run of uppercase letters).
For this purpose here we use a simplified version. In reality the logic is far more complex. In this version there are only two rules:
If
inputconsists of only lowercase letters, then anidentifiermatches theinputonly if there is a splitting ofinputinto substrings, that for each substring there is a word within theidentifierstarting with that substring, in that exact order.Example input:
sboTruthy cases:
SQLiteBindOrColumnIndexOutOfRangeException,SparseBooleanArray, (UPDATE)StringIndexOutOfBoundExceptionFalsy cases:
SeekBar(missingo),StatusBarNotification(theois not at the beginning of a word)If
inputcontains uppercase letters, then a split on theinputmust be made before each uppercase letter when applying Rule 1.Example input:
sbOTruthy cases:
SQLiteBindOrColumnIndexOutOfRangeExceptionFalsy cases:
SparseBooleanArray(theOmust appear at the beginning of a word),StringIndexOutOfBoundException(wrong order)
I/O
Input: two strings, one for input and one for identifier. You can assume that the regex [A-Za-z]+ matches input and the regex [A-Za-z0-9_] matches identifier.
Output: one of the truthy or falsy values. You can choose what value to return as truthy and what as falsy, but your choice must be consistent across all cases. For example you can return 1/0, true/false, π/e or whatever, but they must stay the same across all cases.
Test cases
Each line consists of two strings, namely input and identifier respectively.
Truthy cases:
"sbo" "SparseBooleanArray"
"sbo" "StringIndexOutOfBoundException"
"sbo" "SQLiteBindOrColumnIndexOutOfRangeException"
"sbO" "SQLiteBindOrColumnIndexOutOfRangeException"
"Al" "ArrayList"
"AL" "ArrayList"
"Al" "ALARM_SERVICE"
"As" "ALARM_SERVICE"
"AS" "ALARM_SERVICE"
"SD" "SQLData"
"SqD" "SQLData"
"SqlD" "SQLData"
"SqDa" "SQLData"
"the" "theWord_Example"
"the" "THEWORD2EXAMPLE"
"the" "THEWordEXAMPLE3"
"the" "THEWORDEXAMPLEFOUR"
"thw" "theWord_Example"
"thw" "THEWordEXAMPLE3"
"te" "theWord_Example"
"te" "THEWORD2EXAMPLE"
"te" "THEWordEXAMPLE3"
Falsy cases:
"sbo" "SeekBar"
"sbo" "StatusBarNotification"
"sbO" "StringIndexOutOfBoundException"
"sbO" "SparseBooleanArray"
"AL" "ALARM_SERVICE"
"ASE" "ALARM_SERVICE"
"SQD" "SQLData"
"SqLD" "SQLData"
"SLD" "SQLData"
"SQDt" "SQLData"
"SQDA" "SQLData"
"thw" "THEWORD2EXAMPLE"
"thw" "THEWORDEXAMPLEFOUR"
"te" "THEWORDEXAMPLEFOUR"
Winning Criteria
This is a code-golf, so shortest code of each language wins. Default loopholes are not allowed.
2 Answers 2
Python 2, (削除) 239 (削除ここまで) 227 bytes
lambda a,b:any(re.match(w,''.join(map(str.title,re.sub('(?=[A-Z][a-z])|(?<=[a-z])(?=[A-Z])|(\d)','_',b).split('_'))))for w in g(a))
import re
g=lambda s:s and{c+w for w in g(s[1:])for c in[s[0],'.*'+s[0].upper()][s<'[':]}or{''}
JavaScript (ES6), 177 bytes
Expects (identifier)(input).
S=>g=([c,...s],l=[],o='')=>c?g(s,o?[...l,o]:l,c)|c>{}&g(s,l,o+c):eval(`/~${[...l,o].join`.*~`}/i`).test(S.replace(/./g,(c,i)=>!i|(!/[A-Z]/.test(l)|S[i+1]>'_')&(l=c)<{}?'~'+c:c))
"SQLData", "SQLData"is false? \$\endgroup\$"sqldata", "SQLData"is true. \$\endgroup\$"sbo" "StringIndexOutOfBoundException"match*S*tringIndexOutOf*Bo*undException? \$\endgroup\$