Искаженные номера телефонов

19

Вы знаете, как получить сообщение голосовой почты, и соединение этого человека было не очень хорошим, и вы пытаетесь выяснить, как перезвонить им, но вы не уверены, что это «5» или «8». сказал?

Вот этот вызов.

Хорошая новость заключается в том, что звонящий дважды считывает их номер, но он искажается в обоих местах.

Ваша программа должна принимать следующие данные:

5551231234 / 5551231234

Где первые десять цифр - это первый раз, когда телефонный номер произносится в голосовой почте, а второй набор - во второй раз, когда он произносится. Только ... это будет выглядеть примерно так:

555?ABC1_36? / 55?522_1?234
  • Цифра, за которой следует знак вопроса, означает, что эта цифра лучше всего подходит (например, «5?» Означает «вероятно, 5, сравните с повтором»).
  • Подчеркивание указывает на известную отсутствующую цифру, что-то слишком размытое от статики, чтобы вообще его можно было расшифровать.
  • Буквы - это просто буквы. Обращайтесь с ними как с соответствующими цифрами
    • ABC -> 2, DEF -> 3, GHI -> 4, JKL -> 5, MNO -> 6, PQRS -> 7, TUV -> 8, WXYZ -> 9
    • Все примеры ввода используют заглавные буквы (вы можете спокойно пропустить вызов ToUpper ())
    • Если ваш язык работает лучше в нижнем регистре, вы можете свободно использовать строчные буквы для ввода и пропустить вызов ToLower (). Просто отметьте это в своем ответе.

Вы можете дополнительно принять следующие суждения:

5? / _     -> 5  //5 is the best guess we have, use it
5? / 5?    -> 5  //uncertain, but matching
5? / 4?    -> ?  //conflict
 5 / 4     -> ?  //conflict
5? / 4     -> 4  //solid information overrides possible value
 5 / 4?    -> 5  //solid information overrides possible value
 _ / _     -> ?  //no information available

Кроме того, вы можете предположить, что все входные данные будут содержать десятизначные номера телефонов, не включая вопросительные знаки. Входные данные, не 1234567 / 1234567состоящие из десяти цифр (например ), могут рассматриваться как неразрешимые (вывод Falsey) или выдавать ошибку.

вход

Одна строка символов 0-9A-Z _?/, как описано выше.

Выход

Если его можно проанализировать по одному действительному десятизначному номеру телефона, выведите номер телефона. В противном случае выведите некоторую форму индикации ошибки (например, -1, false или пустую строку).

Самые короткие победы, как обычно.

Примеры входных данных:

1234567890 / 1234567890
1234567890? / 1234567890
123456789_ / 1234567890
1234567890? / 123456789_
1234567890 / 1234567890?
1234567890 / 123456789_
123456789_ / 1234567890?
1234567890? / 1234567890?
1234567890? / 1234567891?
123456789_ / 123456789_
555CALLUS1 / 5552255871
404_12?6039 / 4041?1560_9
_GETREVENGE / 16?36?_2838_
1?691460_50 / 16_14609?50
61?08977211 / 612?897725?1
40?0INSTA__ / 8?00_NSTI?LL
3985_534?10 / 39?8?5053_10
7__7294?737 / 7797299?_37
28?897_384?1 / _8?89763861
271168090_ / 27116800?09
6802?148343 / 67?01148343
94_11628?2?6? / 9491162_47?
17?4285_689 / 1__26?52689
6_311?95_38 / 6731194?7?38
380?7DRAGON / 3807378?5?66
4?647_93236 / 5646?6?9__36
365?268898_ / 366267?7?984
GRATEDBATE / IRATEDBATE
5307_079?93 / ____8_____
535_3_0255 / 52?5_3_024?5
55_____088 / 54?2397207?7?
6_48398_95 / _946?398?6_5?
_0_312_3_1 / 81?53123?1?71
____1_____ / 64?255?508?61
8427820607 / 6?424?8?__6?07
50_3707__6 / 52?8375?74?56
615___8255 / 62?526?983?2?1?
__652618__ / 8365261__0
149___933_ / 1_9677?92?31
___7?281562 / 3438?28154?2
5?7?7?___8?3?7?4 / 57_855837_
605_272481 / 605427__81
86?569__731 / 88560?0?7721
1__91654?15 / 17?9?9165715
800NWABODE / 80069ABI?DE
8___9017_0 / 8_2494?12?9_
_024?5?91?470 / 304?17908?7_
42510704_2 / 4_51070492
9338737_89 / 93_873PLUS
327762_401 / 327_MASH01
33093_2058 / 3309_12058
4061_33578 / 40619_3578
559_383197 / 559938_197
94_9746084 / 9459746_84
1_37655238 / 163POLKA_T
_672FRIZZY / 767237499_
8_76318872 / TIP63188_2
51_8404321 / 5178404_21
358_030314 / 358603_314
2597_85802 / 25979_5802
77141_1408 / 7714_91408
330858_457 / 330_586457
4686079_39 / 46_6079239
86457508_6 / 8_45750826
523226626_ / _23BANNANA
_ISSY_ISSY / 44__9548?79?
6?00B_YJILT / 800289KILL?
2?52803___0 / 1526?0390?61?
FI?ND___T?HE / EAS?T?EREGGS?
0_231?95_38 / 0723194?7?38
0?647_39236 / 0646?6?3__36
025?267798_ / 06?6265?9?984
0061_33578 / _0619_3578

Я только гарантировал, что каждый возможный крайний случай покрыт (первые 11 записей), но кроме этого, он в значительной степени случайный.

Обновить

Четыре записи внизу добавлены с ведущими нулями (по предложению Джонатана Аллана).

Правильный вывод для входных выборок:

https://pastebin.com/gbCnRdLV

Основываясь на выводе записи Джонатана Аллана (форматированный вывод был идеальным).

Draco18s
источник
Должны ли мы принимать входные данные в виде одной строки, разделенной друг от друга " / ", или мы можем просто принять их как два стандартных ввода?
L3viathan
@ L3viathan Я изначально задумывал идею взять одну строку.
Draco18s
7
@ Одна строка Draco18s ничего не ставит перед вызовом
fəˈnɛtɪk
1
@ fəˈnɛtɪk Никто ничего не сказал в песочнице, но я ничего не имею против использования входных пар. Это было так, как я изначально задумал.
Draco18s
1
Кто оставляет голосовую почту, используя буквы для своего номера телефона ?!
Джонатан Аллан

Ответы:

3

Желе , 84 байта

+4 байта - я думаю, что он, вероятно, должен вести себя одинаково во всех случаях, поэтому я преобразовал целочисленные значения поиска клавиатуры с использованием цифр +49Ọ.

”?e‘ḣ@µ”_eḤ‘ẋ@
;Ṃµ68DṬ+3RØAṁẇ@€FT+49Ọȯµ€Fṡ2i”?Ḃ$ÐḟÇ€
ḟ⁶ṣ”/Ç€ZLÐṂ€Q€LỊ$ÐfF€Ḣ€ḟ”_µL⁼⁵ȧ

Функция, которая принимает строку в указанном формате и возвращает номер телефона в виде списка символов или ноль, если он недействителен. Как программа это печатается, как если бы это была строка.

Как это работает, они могут повторить число больше раз
(например "123456789_ / 123456789_ / 1234567890")
... или даже сказать это только один раз, и определенная логика будет применяться.

Попробуйте онлайн! или посмотрите все примеры входных данных .

Как?

”?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)
Джонатан Аллан
источник
Похоже, что может быть ошибка, 55_____088 / 54?2397207?7?следует исправить 5523972088: все недостающие цифры присутствуют, а неопределенные цифры справа доступны слева. Все упрощенные случаи работают, хотя.
Draco18s
Ах, я удалил то, что я считал избыточным фильтром, это не так. Исправление ...
Джонатан Аллан
Был там раньше - и это был не гольф! ;)
Draco18s
Ooof, что заняло у меня некоторое время (я обнаружил другую ошибку, пока я тестировал ее), вернул ее к тому же количеству байтов, что и простое добавление фильтра при исправлении, хотя и так (вот так).
Джонатан Аллан
@ Draco18s - тебе все хорошо? Было бы хорошо дать ожидаемый результат для тестовых случаев в вопросе, или, возможно, просто выделить недействительные.
Джонатан Аллан
7

Python 2 , 314 307 274 байта

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="?"

Попробуйте онлайн!

овс
источник
5

Python 3, 549 530 509 453 449 410 406 394 393 391 байт

Я уверен, что это можно улучшить, но это начало:

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(" / "))

Я использую str.translateдля букв и функцию-обертку, gчтобы сделать входные данные в формате, в котором я хочу их. Фактическая функция fявляется рекурсивной и не работает для неоднозначных входных данных. У меня все еще есть много повторений, так что я уверен, что есть много возможностей для улучшения.

Улучшения:

  • сэкономил 19 байтов путем объединения условий
  • сэкономил 21 байт с троичными
  • благодаря @TuukkaX удалось сэкономить 56 байт, используя словарь вместо словаря вручную
  • сэкономил 4 байта, переключившись на метод, предложенный @ovs, с улучшением @ TuukkaX
  • сохранено 38 байт с улучшениями от @ovs (и удален последний удаляемый пробел)
  • сэкономил 4 байта, поместив определение str.isnumericв качестве аргумента
  • сохранено 12 байтов с объединенными операторами сравнения (например T==q!=O)
  • сохранил 1 байт, превратившись not(e or z)в e+z in(e,z).
  • сэкономил 2 байта, сохранив часто используемые (E,Z)
L3viathan
источник
Он содержит словарь, который не содержит значений по умолчанию в верхней строке. Я ненавижу последовательности 3, но они могут быть заменены на математику.
Yytsi
@ovs Отлично. Алфавит может быть изменен на map(chr,range(65,91))хотя.
Yytsi
2
RE: Делая это вики-сообществом, чтобы отказаться от репутации, консенсуса было бы нет , просто примите любезную помощь и поверьте ей, как у вас.
Джонатан Аллан
1
Я клянусь, каждый раз, когда я возвращаюсь сюда, этот ответ становится короче: D
Draco18s
3

JavaScript (ES6), 180 190 188 байт

Изменить: +10 +9 байт, чтобы соответствовать правилу ложного вывода


Принимает две входные строки в синтаксисе карри (a)(b). Возвращает либо falseлибо строку, представляющую угаданный номер телефона.

a=>b=>!(s=(F=a=>a.match(/(.\??)|_/g).map(([x,y])=>(x<=9?++x:parseInt(x,36)*.32-(x>'Y'))|(x!='_'&!y)*16))(a).map((x,i)=>(x=(d=x^(y=F(b)[i]),x>y)?x:y)&&(d&16|!(d%x))?--x&15:a).join``)[10]&&s

Как это устроено

Шаг № 1 - Разбор входных строк

Сначала мы определим F()функцию, которая переводит строку в массив целых чисел, применяя следующие правила:

  • подчеркивание преобразуется в 0
  • цифра N или эквивалентная буква преобразуется в (N + 1) ИЛИ 16 (например, «2» → 19, «R» → 24)
  • цифра N или эквивалентная буква, за которой следует знак запроса, преобразуется в N + 1 (например, «2?» → 3, «R?» → 8)

Что, наоборот, можно интерпретировать следующим образом:

  • 0 неизвестно
  • [ 1 .. 10 ]ненадежный
  • [ 17 .. 26 ]надежный

Мы применяем F()к обоим aи b. Это дает нам пару целых чисел (x, y) для каждой цифры в номере телефона, что соответствует двум возможным интерпретациям.

Шаг № 2 - угадывание цифр

Для каждой пары (x, y) мы вычисляем:

  • d = x XOR y
  • x = MAX (x, y) надежные значения всегда предпочтительнее ненадежных

Если x == 0 , это означает, что оба ввода являются символами подчеркивания. Итак, цифра в этом случае неизвестна.

Если x! = 0 , мы можем безопасно вывести цифру, если выполняется одно из следующих условий:

condition       | interpretation
----------------+------------------------------------------------------
(d AND 16) != 0 | one input is unreliable and the other one is reliable
d == 0          | both inputs are identical
d == x          | one input is an underscore

Последние два условия могут быть объединены с !(d % x). Отсюда и окончательная формула:

x && (d & 16 || !(d % x))

Если это правда, мы конвертируем x обратно в предполагаемую цифру, вычисляя (x - 1) И 15 .

Контрольные примеры

(Только 50 первых, потому что фрагмент консоли не может поддерживать больше истории вывода.)

Arnauld
источник
1234567890? / 1234567890?должен решить 1234567890. Прямо сейчас ваш код выводит, 123456789?который даже менее информативен, чем ввод. Assume: 5? / 5? -> 5 //uncertain, but matching
Draco18s
@ Draco18s Вопреки тому, что я сказал, я включил 51 контрольный пример . Итак, первый был отброшен и все сдвинуто на один ряд. (Сейчас исправлено. Извините за это.)
Арно
Ааа. Тем не менее, он должен вывести какое-то значение фальсификации или значение ошибки для этих тестовых случаев. Но в остальном выглядит хорошо.
Draco18s
2

Perl 5 , 211 байт

... без отступа и \ n новых строк

@i=map{y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/22233344455566677778889999/;$_}split' / ',shift;
print map{
  $_=join'',map{s,(\d\??|_),,;$1}@i;
  /((\d)\??\2\??|(\d)\??_|_(\d)\??|(\d)\d\?|\d\?(\d))$/;$2//$3//$4//$5//$6//'?'
}1..10

Попробуйте онлайн!

Кжетил С.
источник
Похоже, он возвращает «лучшее, что может» ( 83652618?0), а не какую-то ложь или значение ошибки.
Draco18s
Что и было загадкой, если я не ошибаюсь. Посмотрите на случаи под заголовком «Вы можете дополнительно принять следующие вызовы по решению». Или не?
Кжетил С.
Извините, я так и не получил уведомление о вашем ответе (без упоминания). В разделе, который я сделал для оценочных вызовов, используется знак a, ?указывающий на то, что нет способа разрешить недостающую информацию, которая затем должна перейти к разделу «Вывод»:...Otherwise output some form of error indication (e.g. -1, false, or an empty line).
Draco18s
2

Сетчатка, 150 140 136 байт

Сохранено несколько байтов благодаря Kritixi Lithos

T`?L`#22233344455566677778889
./.

(?<=(\d)(\w#?){9}).#|.#(?=(\w#?){9}(\d)(?!#))
$1$4
#

_(?=.{9}(.))|(?<=(.).{9})_
$1$2
^(\d*)\1$|.*
$1

Попробуйте онлайн!

Объяснение:

Первая строка преобразует все ?входные данные в #и все буквы в их числовые эквиваленты. Затем мы удаляем пробелы и /из ввода. Следующие две строки относятся к случаям «предположение против определенности» (например 5? \ 4, будут заменены на 4 \ 4). После удаления всех #s в строках 8 и 9 рассматриваются _случаи «число против » ( _ \ 3становится 3 \ 3). Затем, если обе половины строки совпадают, мы сохраняем первые 10 цифр. В противном случае номер телефона недействителен, поэтому мы удаляем все.

Альтернативное 160-байтовое решение, которое работает для телефонных номеров произвольной длины (и равного размера): TIO

математик наркоман
источник
Вы можете изменить , (/|_)чтобы [/_]спасти 1 байт. Кроме того, я думаю, что вы можете использовать ;вместо того, xчтобы [^x]стать\w
Kritixi Lithos
1

PHP, 251 236 байт

for(;a&$c=preg_replace(["#[^_?](?!\?)#","#_#"],["$0k","?<"],join("-",$argv))[++$i];)${$k+="-"==$c}.=$c<_&$c>=A?0|(ord($c)-($c>W)-($c>P)-59)/3:$c;for(;$c=${1}[$k+1];)echo($n=${1}[$k])==($m=${2}[$k++])|($b=${2}[$k++])!=$c?$c>$b?$n:$m:"?";

принимает данные из командной строки; запустить -nrили попробовать это онлайн .

сломать

# A: transform input
                                    # 2. replace single chars with two-character chunk and make sortable:
                                    #   replace "_" with "?<", append "k" to everything else not followed by "?"
for(;a&$c=preg_replace(["#[^_?](?!\?)#","#_#"],["$0k","?<"],join("-",$argv))[++$i];)    # (unknown "<" < unsure "?" < certain "k")
${$k+="-"==$c}.=                # if "-", next argument
        $c<_&$c>=A              # if letter
            ?0|(ord($c)-($c>W)-($c>P)-59)/3 # then translate to digit
            :$c                             # else don´t
    ;
# B: evaluate
for(;$c=${1}[$k+1];)            # loop through arguments: $c=command 2
    echo
        ($n=${1}[$k])                   # $n=digit 2
        ==                          # if digits are equal
        ($m=${2}[$k++])                 # $m=digit 3
        |
        ($b=${2}[$k++])             # $b=command 3
        !=$c                        # or "commands" are not
            ?$c>$b?$n:$m            # then get the one with the more definitive "command"
            :"?"                    # else conflict/unknown
    ;

golfings

  • preg_replace первый: -8 байт
  • join: -2
  • $$kвместо $t[$k]: -5
Titus
источник
1

PHP, 200 + 8 байт

вдохновленный решением Arnaulds .

for($s=join($argv);$c=ord($s[$i++]);$i+=$x)$t[]=$c>90?63:15&($c<65?$c:($c-($c>80)-($c>87)-59)/3)|16*$x="?"==$s[$i];for(;$p++<10;)echo chr(($e=$t[$p]^$d=$t[$p+10])&48|!(15&$e)?min($t[$p],$d)&15|48:63);

принимает входные данные из аргументов командной строки; запустить -nrили попробовать это онлайн .

изменения, соответствующие ограничению вывода ошибок: (выведите Xнеполное число):

  • удалить |48(-3 байта)
  • заменить echo chr(...);на $r.=...;echo$r>1e10?X:$r;(+11 байт)

сломать

for($s=join($argv);$c=ord($s[$i++]);    # loop through characters of arguments
    $i+=$x)                             # skip "?"
$t[]=
    $c>90                               # if "_"
        ?63                             # then 32+16+15
        :                               # else
            15&(                            # lower 4 bits of
            $c<65                               # if digit
            ?$c                                 # then digit
            :($c-($c>80)-($c>87)-59)/3          # else letter mapped to digit
        )
        |16*$x="?"==$s[$i]                  # if next char is "?", add 16
;
for(;$p++<10;)echo chr( # loop through translated arguments
    (
        $e=$t[$p]^      # 2. $e=difference
        $d=$t[$p+10]    # 1. $d=char from 2nd argument
    )&48                # if certainties differ
    |!(15&$e)           #    or digits do not
    ?min($t[$p],$d)&15|48   # then pick the more definite digit (15|48 -> "?")
    :63             # else "?"
);

golfings

  • обойти preg_replace_callback(-10 байт)
  • полагаться на 10-значный ввод (-9)
  • и дополнительная игра в гольф (-8)
  • удаленный joinразделитель (-7)
  • перенес $xзадание в конец (-2)
Titus
источник