Garbled Phone Numbers
Python 2, 314 307 274 bytes
lambda s:g(*''.join(q<n<"["and`(int(n,36)-4-(n>"R")-(n>"Y"))//3`or n for n in s).split(" / "))
def g(a,b,s=str.startswith):
if b:c,d,e,f=a[0],a[1:],b[0],b[1:];b=(c==e and[c,q][c=="_"]or"_"in c+e and min(c,e)or[q,c,e][s(f,q)-s(d,q)])+g(d[s(d,q):],f[s(f,q):])
return b
q="?"
Try it online!
Python 3, 549 530 509 453 449 410 406 394 393 391 bytes
I'm sure this can be improved, but it's a start:
def f(e,z,q="?",u=str.isnumeric):
if e+z in(e,z):return""
o,O,t,T,*x=e[0],e[1:2],z[0],z[1:2],e[1:],z[1:]
if"?"in o+t:return f([e,x[0]][o==q],z)
if u(o):
if u(t):return t+f(*x)if O==q!=T else o+f(*x)if o==t or T==q!=O else 1
return o+f(*x)
if u(t):return t+f(*x)
def g(s):
for a,b in zip(map(chr,range(65,91)),"2223334445556667777888999"):s=s.replace(a,b)
return f(*s.split(" / "))
I'm using str.translate
for the letters, and a wrapper function g
to make the inputs in the format in which I want them. The actual function f
is recursive, and will fail for ambiguous inputs. I still have lots of repititions in there though, so I'm sure there's lots of room for improvement.
Improvements:
- saved 19 bytes by combining conditions
- saved 21 bytes with ternaries
- saved 56 bytes using a dictionary comprehension instead of the manual dictionary, thanks to @TuukkaX
- saved 4 bytes by switching to the method suggested by @ovs, with @TuukkaX's improvement
- saved 38 bytes with improvements from @ovs (and the last removable whitespace removed)
- saved 4 bytes by putting defining
str.isnumeric
in a keyword argument - saved 12 bytes with combined comparison operators (e.g.
T==q!=O
) - saved 1 byte by turning
not(e or z)
intoe+z in(e,z)
. - saved 2 bytes by saving the frequently used
(E,Z)
Jelly, 84 bytes
+4 bytes - I think it should probably behave the same in all cases, so I've converted the keypad lookup integers back to digit-characters using +49Ọ
.
”?e‘ḣ@µ”_eḤ‘ẋ@
;Ṃµ68DṬ+3RØAṁẇ@€FT+49Ọȯµ€Fṡ2i”?Ḃ$ÐḟÇ€
ḟ⁶ṣ”/Ç€ZLÐṂ€Q€LỊ$ÐfF€Ḣ€ḟ”_µL⁼⁵ȧ
A function which takes the string in the specified format and returns the phone number as a list of character or zero if invalid. As a program this is printed as if it were a string.
The way it works they could repeat the number more times
(e.g. "123456789_ / 123456789_ / 1234567890"
)
...or even only say it once, and the logic defined will apply.
Try it online!, or see all the sample inputs.
How?
”?e‘ḣ@µ”_eḤ‘ẋ@ - Link 1, helper to vary the length of a 2-slice: list s
”? - literal '?'
e - exists in s (1 or 0)
‘ - increment (2 or 1)
ḣ@ - head with reversed @rguments (s or s[:1] - removes 2nd value if not '?')
µ - monadic chain separation, call that t
”_ - literal '_'
e - exists in t (1 or 0)
Ḥ - double (2 or 0)
‘ - increment (3 or 1)
ẋ@ - repeat t that many times (t*3 or t - [`_`]->['_','_','_'])
;Ṃµ68DṬ+3RØAṁẇ@€FT+49Ọȯµ€Fṡ2i”?Ḃ$ÐḟÇ€ - Link 2, reformat a phone number: char list of [0-9][A-Z], p
; - concatenate p with
Ṃ - minimum of p - (?<_<0<1<...<9<A<...<Z - never "?" however, since it only follows a digit.)
- - this is simply to make a 2-slice with the last character on the left, as used at the very end of this link.
µ - monadic chain separation call that q
µ€ - monadic chain separation, for €ach v in q do:
68 - literal 68
D - cast to a decimal list - [6,8]
Ṭ - untruth - [0,0,0,0,0,1,0,1]
+3 - add 3 - [3,3,3,3,3,4,3,4]
R - range - [[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3],[1,2,3,4],[1,2,3],[1,2,34]]
ØA - uppercase alphabet - ABCDEFGHIJKLMNOPQRSTUVWXYZ
ṁ - mould like the range ^ - [ABC,DEF,GHI,JKL,MNO,PQRS,TUV,WXYZ]
ẇ@€ - sublist v exists in that? for €ach, with reversed @rguments
F - flatten (e.g. 'E' -> [0,1,0,0,0,0,0,0]; '4' -> [0,0,0,0,0,0,0,0]
T - truthy indexes (e.g. 'E' -> [2]; '4' -> [])
+49 - add 49
Ọ - cast to character
ȯ - or (e.g. 'E' -> [3]; '4' -> '4')
F - flatten
ṡ2 - all slices of length 2
Ðḟ - filter discard if:
$ - last two links as a monad:
i - first index of
”? - literal '?' (first index returns 0 if none exists)
Ḃ - mod 2 (so this filter discards pairs starting with '?')
Ç€ - call the last link (1) as a monad for €ach slice
ḟ⁶ṣ”/Ç€ZLÐṂ€Q€LỊ$ÐfF€Ḣ€ḟ”_µL⁼⁵ȧ - Main link: string (or char list) s
ḟ - filter discard any:
⁶ - literal ' '
ṣ - split on:
”/ - literal '/'
Ç€ - call the last link (2) as a monad for €ach
Z - transpose
ÐṂ€ - filter, for €ach, keep items with minimal:
L - length
Q€ - de-duplicate €ach
Ðf - filter keep items with:
$ - last two links as a monad:
L - length
Ị - insignificant? (=1 effectively here)
F€ - flatten €ach
Ḣ€ - head €ach
ḟ - filter discard any of:
”_ - literal '_'
µ - monadic chain separation, call that r
L - length(r)
⁵ - literal 10
⁼ - equal?
ȧ - and r (0 if r did not result in a 10-digit list, else r)