Algorytm Luhna do weryfikacji numerów kart kredytowych itp

49

Wyzwanie

Napisz najkrótszy program lub funkcję do obliczenia algorytmu Luhna do weryfikacji liczb (karty kredytowej).

Algorytm Luhna wyjaśniony

Z RosettaCode ten algorytm na potrzeby tego wyzwania jest określony jako taki, z przykładowym wejściem 49927398716:

Reverse the digits, make an array:
    6, 1, 7, 8, 9, 3, 7, 2, 9, 9, 4
Double the numbers in odd indexes:
    6, 2, 7, 16, 9, 6, 7, 4, 9, 18, 4
Sum the digits in each number:
    6, 2, 7, 7, 9, 6, 7, 4, 9, 9, 4
Sum all of the numbers:
    6 + 2 + 7 + 7 + 9 + 6 + 7 + 4 + 9 + 9 + 4 = 70
If the sum modulo 10 is 0, then the number is valid:
    70 % 10 = 0 => valid

Zasady IO

Dane wejściowe : ciąg lub liczba (do wyboru) w wybranym formacie wejściowym / wyjściowym języka

Wyjście : odpowiednio wartość prawdy lub fałszu , wskazująca, czy dane wejściowe są prawidłowe zgodnie z powyższym testem.

Uwagi / wskazówki

  • Staraj się nie publikować przypadkowo własnych numerów kart kredytowych lub kont, jeśli używasz ich do testowania :)

  • Jeśli dane wejściowe są niepoprawne i niemożliwe do przetworzenia przy użyciu określonego algorytmu (tj. Zbyt krótki, aby pracować z nim), możesz zrobić, co chcesz, w tym wysadzić mój komputer.

  • Jednak poprzedni punkt nie oznacza, że ​​Twój język może robić, co chce, z liczbami, które są zbyt duże, aby można go było obsługiwać. Jeśli twój język nie jest w stanie obsłużyć przypadku testowego, rozważ wzięcie ciągu jako danych wejściowych.

Przykłady

Poniższe przykłady zostały sprawdzone przy pomocy tego skryptu Python ; jeśli uważasz, że ktoś się myli lub masz pytanie, po prostu ping @cat.

49927398716      True
49927398717      False
1234567812345670 True    
1234567812345678 False
79927398710      False
79927398711      False
79927398712      False
79927398713      True
79927398714      False
79927398715      False
79927398716      False
79927398717      False
79927398718      False
79927398719      False
374652346956782346957823694857692364857368475368 True
374652346956782346957823694857692364857387456834 False
8 False **
0 True  **

** zgodnie z implementacją Pythona, ale możesz zrobić wszystko, ponieważ są one zbyt krótkie, aby można je było spełnić poprzez ścisłe przestrzeganie specyfikacji.


Jeśli którakolwiek z powyższych unieważnia istniejące odpowiedzi (choć uważam, że nie powinno to być możliwe), to te odpowiedzi są nadal ważne. Jednak nowe odpowiedzi, aby były poprawne, powinny być zgodne z powyższą specyfikacją.

Tabela liderów

Chris Laplante
źródło

Odpowiedzi:

21

Golfscript - 24 znaki

-1%{2+0!:0)*109%+}*10%8=

Wyjaśnienie:

  1. -1% odwraca ciąg
  2. {rozpoczyna blok (którego używamy jako pętli). Każdy znak w łańcuchach jest wypychany, ponieważ ma wartość ascii.
    1. 2+ dodaje 2. (wartość ascii cyfry wynosi 48 + n, więc mamy teraz 50 + n, a ostatnia cyfra to n)
    2. 0!:0 odwraca wartość 0 i zapisuje ją (wszystko jest zmienną), więc mamy 1 na pierwszej iteracji, 0 na drugiej itd.
    3. )* dodaje jeden do tej wartości i mnoży ją, więc mnożymy przez 2, potem 1, potem 2 itd.
    4. 109% jest resztą modulo 109. Wpływa to tylko na wartości 5-9, które zostały podwojone i redukuje je do prawidłowej wartości.
    5. + dodaje tę wartość do bieżącej sumy
  3. }*kończy blok i wykonuje operację składania. Najpierw wypychany jest pierwszy znak (ponieważ się odwróciliśmy, jest to cyfra kontrolna). Następnie na przemian pchanie i wykonywanie bloku. Dlatego używamy wartości ascii pierwszego znaku jako wartości początkowej dla sumy bieżącej.
  4. 10% bierze resztę modulo 10.
  5. 8= zwróci 1, jeśli wartość wynosi 8. Używamy tego, ponieważ nie znormalizowaliśmy pierwszego wypychanego znaku (cyfry kontrolnej).

Można by pomyśleć, że 8-zamiast 2+ocalić postać możemy użyć, zmieniając 109%na 89%, z wyjątkiem tego, że musielibyśmy dodać spację, aby -odjąć (zamiast -0).

Nabb
źródło
11

GolfScript, 44 znaki

-1%{16%}%2/1,\+{(\.{0=2*.9>9*-+}{;}if+}*10%!

Wybrany komentarz

Co ciekawe, pierwsze dwa poniższe elementy pokazują trzy zupełnie różne zastosowania %operatora: wybór tablicy, mapa i mod. Większość operatorów GolfScript jest „zależnych od kontekstu”, co zapewnia im bardzo rozbieżne zachowania w zależności od typów argumentów.

  1. -1%odwraca ciąg. Jest to ważne, ponieważ pary cyfr liczone są od prawej.
  2. {16%}% konwertuje wszystkie cyfry ASCII na liczby, modyfikując je za pomocą 16.
  3. 2/ dzieli tablicę na grupy po 2.
  4. 1,to tani sposób na zrobienie tego [0].
  5. \+skutecznie dodaje cyfrę 0 do tablicy cyfr. Robi to poprzez zamianę, a następnie konkatenację.

Wartość 0 jest dodawana do przygotowania do złożenia, które nastąpi w następnej kolejności. Zamiast przyjmować jawną wartość początkową, fold GolfScript używa pierwszego elementu w tablicy jako wartości początkowej.

Teraz spójrzmy na faktyczną funkcję składania. Ta funkcja przyjmuje dwa argumenty: wartość zagiętą i bieżący element w tablicy (która w tym przypadku będzie tablicą 2 lub (nietypowo) 1, z uwagi na 2/wcześniejsze). Załóżmy, że argumenty są 1 [2 3].

  1. (\.dzieli lewy element tablicy, przesuwa pozostałą tablicę na przód, a następnie kopiuje. Stos wygląda teraz tak: 1 2 [3] [3].
  2. Do ifsprawdza czy tablica jest pusta (co ma miejsce w przypadku ostatniej grupy, gdy do czynienia z dziwnym wielkości numer konta). Jeśli tak, to nie dzieje się żadne specjalne przetwarzanie (wystarczy usunąć pustą tablicę).
  3. Dla parzystej grupy:
    1. 0= pobiera pierwszy (tylko w tym przypadku) element tablicy. 1 2 3
    2. 2* podwaja liczbę. 1 2 6
    3. .9>9*- odejmuje 9 od liczby, jeśli jest większa niż 9. Zaimplementowane jako: skopiuj liczbę, porównaj z 9, pomnóż wynik (czyli 0 lub 1) przez 9, a następnie odejmij. 1 2 6
    4. + w końcu dodaje to do pierwszego numeru. 1 8
  4. +(po if) dodaje wynik ifdo pierwotnej wartości, co skutkuje nową złożoną wartością.

Po zakończeniu składania po prostu modujemy za pomocą 10 ( 10%) i negujemy wynik ( !), tak aby zwracać 1 iff suma jest wielokrotnością 10.

Chris Jester-Young
źródło
Wydaje się, że zwraca 0 dla przykładowego numeru na wikipedii (49927398716)
gnibbler
nm. Zapomniałem użyćecho -n
gnibbler
1
@gnibbler: Haha, fail. :-P (Poważnie, też mnie to uraziło podczas pierwszych testów.)
Chris Jester-Young
1
Kilka miejsc, w których można zapisać kilka łatwych postaci. -1% 2/można połączyć w -2/. 1,można zastąpić przez 0(0 jest przymuszane do tablicy, a następnie +jest konkatenowane). 9>9*-można zastąpić przez 9>+(ponieważ zajmujemy się tylko ostatnią cyfrą). Ponadto sprawdzanie nieparzystych długości jest nieco długie, a użycie .,2%,\+jest krótsze. Po wykonaniu tej czynności, możemy również zmienić {16%}%i (\0=na {16}/(wewnątrz pętli). Po wykonaniu wszystkich, że będzie to wyglądać mniej więcej tak: .,2%,\+-2/0\+{{16%}/2*.9>+++}*10%!.
Nabb
@Nabb: Dzięki! Włączę je do mojego rozwiązania, chociaż wygląda na to, że już masz taki, który skopie poważne tyłki. :-)
Chris Jester-Young,
11

Python, 73 69 znaków

def P(x):D=map(int,x);return sum(D+[d-d/5*9for d in D[-2::-2]])%10==0
Keith Randall
źródło
4
Możesz zapisać dwa kolejne znaki, nie zapętlając wstecz: D[-2::-2]-> D[1::2]ponieważ kolejność sumy nie jest ważna :)
ThinkChaos
==0można skrócić do<1
Black Owl Kai
10

Python 3, 77 bajtów

c=lambda a:sum(sum(divmod(int(a[-e-1])<<e%2,10))for e in range(len(a)))%10==0
Alexandru
źródło
9

C # 119 znaków:

bool l(string n){return(String.Join("",n.Reverse().Select((x,i)=>(x-48)*(i%2<1?1:2)+"").ToArray()).Sum(x=>x-48))%10<1;}

Nie zbyt złe dla n00b kod golfowego w statycznie wpisywanych języka, mam nadzieję.

Można to zmniejszyć do 100 :

bool l(string n){return String.Join("",n.Reverse().Select((x,i)=>(x-48)*(i%2+1))).Sum(x=>x+2)%10<1;}
mootinator
źródło
To dobry pomysł i ciekawe podejście, ale wydaje się, że nie działa. Przynajmniej nie z moimi kilkoma testami. Wygląda na to, że „i” w pierwszej lambda ma być indeksem znaku w ciągu. Czy to działa tak, jak powinno? Jeśli tak, to dlaczego odwracasz ciąg znaków, a następnie modyfikujesz go na podstawie pozycji indeksu? Wydaje się trochę zbędny, nie?
Nellius
Przetestowałem tylko jedną z moich kart kredytowych i kilka z nich po jednym błędzie TBH. (Korzystanie z debugera VS 2008). Algorytm ma podwoić się co drugą cyfrę, zaczynając od cyfry LAST. Gdybym nie odwrócił łańcucha, byłoby niepoprawne dla łańcuchów o nieparzystych długościach.
mootinator
Okazało się, że miałem wynik i%2<1?1:2wstecz. Dzięki.
mootinator
8

Golfscript - 34 znaki

{15&}%.-2%\);-2%{.+(9%)}%+{+}*10%!

Przykładowy numer ze strony wikipedii 4992739871

{15&}%  does a bitwise and of each ascii digit with 00001111
        now I have a list of digits 
        [4 9 9 2 7 3 9 8 7 1 6]
.       makes a copy of the list, now I have two identical lists
        [4 9 9 2 7 3 9 8 7 1 6] [4 9 9 2 7 3 9 8 7 1 6]
-2%     like [::-2] in python takes every second element in reverse
        [4 9 9 2 7 3 9 8 7 1 6] [6 7 9 7 9 4]
\       swap the two lists around
        [6 7 9 7 9 4] [4 9 9 2 7 3 9 8 7 1 6]
);      drop the last digit off the list
        [6 7 9 7 9 4] [4 9 9 2 7 3 9 8 7 1]
-2%     same as before
        [6 7 9 7 9 4] [1 8 3 2 9]
{       for each item in the list ...
.+      ... double it ...
(       ... subtract 1 ...
9%      ... mod 9 ...
)}%     ... add 1 ...
        [6 7 9 7 9 4] [2 7 6 4 9]
+       join the two lists
        [6 7 9 7 9 4 2 7 6 4 9]
{+}*    add the elements up
        70
10%     mod 10
        0
!       invert the result
        1
gnibbler
źródło
Jest .+(9%)to bardzo innowacyjne (w każdym razie dla mnie). Lubię! +1
Chris Jester-Young
Niestety, GolfScript potrzebuje operatora partycjonowania, więc nie musisz robić tego „odrzuć element końcowy i powtórz” bzdury. :-)
Chris Jester-Young
1
@Chris, dowiedziałem się o tym wiele lat temu pod nazwą „casting nines”. Jest to dobry sposób na podwójne sprawdzenie dodawania i mnożenia
odręcznie
3
To nie zadziała, gdy wartość 0 zostanie podwojona ( 0(9%)wynosi 9, a nie 0).
Nabb
8

PHP, 108 bajtów

<?function v($s,$t=0){for($i=strlen($s);$i>=0;$i--,$c=$s[$i])$t+=$c+$i%2*(($c>4)*-4+$c%5);return!($t % 10);}
Juan
źródło
7

Ruby - 85 znaków

def f s
l=s.size
s.chars.map{|k|(i=k.to_i*((l-=1)%2+1))%10+i/10}.inject(:+)%10==0
end
Nemo157
źródło
Prawdopodobnie wiesz o tym, ale możesz zrobić .sum zamiast .inject (: +), aby zaoszczędzić 7 bajtów
Håvard Nygård
7

Haskell, 96 bajtów

Musi być lepszy / krótszy sposób, ale oto moje rozwiązanie Haskell zawierające 96 znaków :

l=(==0).(`mod`10).sum.zipWith($)(cycle[id,\x->x`mod`5*2+x`div`5]).reverse.map((+(-48)).fromEnum)

Niestety z tej digitToIntfunkcji można korzystać tylko wtedy, gdy import Data.Charnajpierw. W przeciwnym razie mogłem obniżyć do 88 znaków, zastępując ((+(-48)).fromEnum)je digitToInt.

sepp2k
źródło
6

Windows PowerShell, 82

filter f{!((''+($_[($_.length)..0]|%{+"$_"*($i++%2+1)})-replace'.','+$&'|iex)%10)}

Historia:

  • 2011-02-13 03:08 (84) Pierwsza próba.
  • 2011-02-13 12:13 (82) Nie muszę się przyłączać, ponieważ przestrzenie nie ranią. +1 + +3nadal można ocenić.
Joey
źródło
5

Q, 63

{0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}

stosowanie

q){0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}"79927398711"
0b
q){0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}"79927398712"
0b
q){0=mod[(+/)"I"$(,/)($)($)@["I"$'x;1+2*'(!)(_)((#)x)%2;*;2];10]}"79927398713"
1b
tartin
źródło
47 bajtów z {0=mod[sum"J"$raze($)($)x*#:[x]#1 2]10}"I"$'(|)innym sposobem na podwojenie indeksów nieparzystych.
streetster
5

D, 144 bajty

bool f(S)(S s){int t(C)(C c){return to!int(c)-'0';}int n,v;foreach(i,c;array(retro(s))){v=i&1?t(c)*2:t(c);n+=v>=10?v%10+v/10:v;}return n%10==0;}

Bardziej czytelnie:

bool f(S)(S s)
{
    int t(C)(C c)
    {
        return to!int(c) - '0';
    }

    int n, v;

    foreach(i, c; array(retro(s)))
    {
        v = i & 1 ? t(c) * 2 : t(c);

        n += v >= 10 ? v % 10 + v / 10 : v;
    }

    return n % 10 == 0;
}
Jonathan M. Davis
źródło
5

APL, 28 bajtów

{0=10|+/⍎¨∊⍕¨v×⌽2-2|⍳⍴v←⍎¨⍵}

Widok rozstrzelony

{                     v←⍎¨⍵}  ⍝ turn the string into a numeric vector of its digits, v
                2-2|⍳⍴v       ⍝ make a vector of the same length, with 2 in every 2nd place
             v×⌽              ⍝ multiply it with v, starting from the right
          ∊⍕¨                 ⍝ turn each component into a string and collect all the digits
      +/⍎¨                    ⍝ turn each digit again into a number and sum them
 0=10|                        ⍝ check whether the sum is a multiple of 10

Przykłady

      {0=10|+/⍎¨∊⍕¨v×⌽2-2|⍳⍴v←⍎¨⍵} '79927398713'
1
      {0=10|+/⍎¨∊⍕¨v×⌽2-2|⍳⍴v←⍎¨⍵} '123456789'
0
Tobia
źródło
1
-2:{0=10|+/⍎¨∊⍕¨⍵×⌽2-2|⍳⍴⍵}⍎¨
Adám
4

PowerShell 123

filter L($x){$l=$x.Length-1;$l..0|%{$d=$x[$_]-48;if($_%2-eq$l%2){$s+=$d}elseif($d-le4){$s+=$d*2}else{$s+=$d*2-9}};!($s%10)}
Ty Auvil
źródło
4

Perl, 46 42 41 bajtów

Obejmuje +1 dla -p

Podaj dane na STDIN:

luhn.pl <<< 79927398713

luhn.pl:

#!/usr/bin/perl -p
s%.%$=-=-$&-$&*1.2*/\G(..)+$/%eg;$_=/0$/
Ton Hospel
źródło
Czy możesz wyjaśnić, jak to działa? Wydaje się, że malejesz według meczu, a następnie także razy meczu 1,2, ale tylko na prawidłowych pozycjach. Dlaczego 1.2? Nie powinno tak być $=-=-$&-$&*/\G(..)+$/?
msh210
3
@ msh210: Koduje efekt mnożenia przez 2. 0..4* 2 daje, 0, 2, 4, 6, 8ale 5..9podaje, 10,12,14,16,18której suma 1 3 5 7 9ma te same ostatnie cyfry, 11 13 15 17 19co te same wartości 0..9 * 2.2, jakbyś obciął liczbę całkowitą. Pierwszy $&już przyczynia się do tego 1, więc korekta 1.2jest nadal potrzebna. $=może przechowywać tylko liczby całkowite i zaczyna się od wartości, która kończy się na 0, więc dba o obcięcie. Wartości ujemne są potrzebne, ponieważ /\G/regex zmienia dowolne wartości $&nadal na stosie ewaluacyjnym, więc należy je zmienić
Ton Hospel 22.04.16
O. Znakomity! I dzięki za wyjaśnienie.
msh210
3

JavaScript (ES6), 61 bajtów

Nie konkuruje, ponieważ JavaScript był bardzo różny w 2011 roku.

Suma cyfr 2*nto, 2*njeśli n in 0..4, 2*n-9jeśli n in 5..9. To powiedziawszy, cała suma może być obliczona w jednym kroku.

s=>!([...s].reduceRight((t,d)=>t-d-i++%2*(d>4?d-9:d),i=0)%10)
edc65
źródło
3

Galaretka , 12 11 bajtów

ṚḤJḤ$¦DFS⁵ḍ

Wypróbuj online! (ze wszystkimi przypadkami testowymi)

Jak to działa

ṚḤJḤ$¦DFSḍ⁵  - Main link. Argument: n (integer) e.g. 49927398716
Ṛ            - Reverse. Casts a number to digits     [6, 1, 7, 8, 9, 3, 7, 2, 9, 9, 4]
     ¦       - Sparse application. Apply the next command to the given indicies
 Ḥ           -   Command: Double
    $        -   Indicies:
  J          -     range(length)...                  [1, 2 , 3, 4, 5, 6, 7, 8, 9, 10, 11]
   Ḥ         -     doubled.                          [2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22]
             - Doubles elements at odd indicies      [6, 2, 7, 16, 9, 6, 7, 4, 9, 18, 4]
      D      - Split each into digits                [6, 2, 7, [1, 6], 9, 6, 7, 4, 9, [1, 8], 4]
       F     - Flatten                               [6, 2, 7, 1, 6, 9, 6, 7, 4, 9, 1, 8, 4]
        S    - Sum                                   70
          ḍ  - Divisible by... 
         ⁵   -   10?                                 1

Alternatywnie, dla 12 bajtów:

ṚḤJḤ$¦DFSḍ@⁵
Cairney Coheringaahing
źródło
3

8086 Montaż , IBM PC DOS,29 28 25 23 bajty

; Perform LUHN check
; Input: SI = card num string, CX = length
; Output: ZF = 1 if valid, ZF = 0 if not valid
    LUHN    MACRO
            LOCAL DIGIT_LOOP, EVEN
03 F1       ADD  SI, CX         ; start at end of input string 
FD          STD                 ; set LODSB direction to decrement 
    DIGIT_LOOP:
AC          LODSB               ; load next digit into AL, decrement SI
2C 30       SUB  AL, '0'        ; convert ASCII char to binary value 
F7 DA       NEG  DX             ; flip DX to alternate odd/even index
78 06       JS   EVEN           ; if even index, do not double and sum digits 
D0 E0       SHL  AL, 1          ; double the value 
D4 0A       AAM                 ; BCD convert to split digits (ex: 18 = 12H --> 0108H) 
02 DC       ADD  BL, AH         ; add tens digit to running sum 
    EVEN:
02 D8       ADD  BL, AL         ; add ones digit to running sum 
E2 ED       LOOP DIGIT_LOOP 
93          XCHG BX, AX         ; sum is in BL, move to AL for conversion
D4 0A       AAM                 ; BCD convert AL, set ZF=1 if low digit is 0
    ENDM

Wykorzystuje (nadużywa) instrukcje BCD do binarnego x86 do obsługi dzielenia i modulo 10sprawdzania poszczególnych cyfr . Okazuje się, że instrukcje AAMi AADwykonują BCD / binarną konwersję wartości bajtów (co może być bardzo przydatne), mimo że nie zostały one udokumentowane lub opisane jako ogólne wykonywanie tej funkcji.

Dla wszystkich oficjalnych wersjach IBM / MS DOS, AXa BXinicjowane są 0000na starcie ( ref , ref ) i DXaby CS, który jest wartością 12-bitowy więc gwarancją niezerowe i pozytywne. W ten sposób możemy zagwarantować, BXto 0i może przerzucić / flop DXdo określenia parzyste / nieparzyste cyfry miejsca.

Przykładowe dane wyjściowe:

wprowadź opis zdjęcia tutaj

Pobierz program testowy LUHN.COM IBM PC DOS.

640 KB
źródło
2

Scala: 132

def q(x:Int)=x%10+x/10
def c(i:String)={val s=i.reverse
(s(0)-48)==10-(s.tail.sliding(2,2).map(n=>(q((n(0)-48)*2)+n(1)-48)).sum%10)}

wezwanie:

c("79927398713")
  • rewers („79927398713”) = 31789372997
  • s (0), s.tail: (3) (1789372997)
  • przesuwne (2,2) = (17 89 37 29 97)
  • mapa (q ((n (0) -48 * 2 + n (1) -48)) => q (('1' - '0') * 2) + '7' - '0') = 1 * 2 + 7
nieznany użytkownik
źródło
2

JavaScript 1.8: 106 znaków

Oto oryginalne rozwiązanie, które wpadłem na pomysł, zanim znalazłem ten post:

function(n){return!(n.split('').reverse().reduce(function(p,c,i){return(+c&&((c*(1+i%2)%9)||9))+p},0)%10)}

Czytelna forma:

function luhnCheck(ccNum) {
    return !(                                  // True if the result is zero.
             ccNum.split('').
               reverse().                      // Iterate over the string from rtl.
               reduce(function(prev, cur, idx) {
                 return prev +                 // Sum the results of each character.
                        (+cur &&               // If the current digit is 0, move on.
                         ((cur * (1 + idx % 2) // Double cur at even indices.
                           % 9) || 9));        // Sum the digits of the result.
               }, 0)
            % 10);                             // Is the sum evenly divisible by 10?
}
kojiro
źródło
2

K4, 35 bajtów

{~.*|$+/.:',/$x*1+1{y;~x}\|x:|.:'x}
Aaron Davies
źródło
2

Retina , 43 42 bajty

Siatkówka jest (znacznie) nowsza od tego wyzwania.


;
r`(.);.
$1$&
\d
$*
1+
$.&
.
$*
$
$._
0$

Wiodąca pusta linia jest znacząca.

Drukuje 0dla fałszerstwa i 1dla prawdziwych wyników.

Wypróbuj online! (Nieznacznie zmodyfikowany, aby uruchomić wszystkie przypadki testowe jednocześnie).

Wyjaśnienie


;

Wstaw ;w każdej pozycji, aby oddzielić cyfry.

r`(.);.
$1$&

Od tego momentu rwielokrotnie dopasowujemy dwie cyfry i podwajamy lewą. W ten sposób unikamy kosztownego cofania listy.

\d
$*

Dopasowujemy każdą cyfrę i konwertujemy ją na tyle 1s (to znaczy przekształcamy każdą cyfrę w unarną).

1+
$.&

To dopasowuje każdą liczbę jednoargumentową i konwertuje ją z powrotem na dziesiętne, zastępując ją długością. W połączeniu z poprzednim etapem dodaje to podwojone cyfry.

.
$*

Ponownie dopasowujemy każdą postać i przekształcamy ją w tyle 1s. Oznacza to, że każdą cyfrę przeliczamy indywidualnie z powrotem na jednoargumentowy. To również pasuje do ;separatorów, które w konwersji są traktowane jako zera, co oznacza, że ​​są po prostu usuwane. Ponieważ wszystkie liczby jednoargumentowe są teraz ściśnięte razem, automatycznie dodaliśmy jednoargumentowe przedstawienie wszystkich cyfr razem.

$
$._

Na końcu wstawiamy długość całego łańcucha, tj. Dziesiętną reprezentację jednoargumentowej sumy kontrolnej.

0$

Na koniec zliczamy liczbę dopasowań tego wyrażenia regularnego, tzn. Sprawdzamy, czy reprezentacja dziesiętna kończy się 0, drukując, 0czy 1odpowiednio.

Martin Ender
źródło
2

PowerShell, 74 bajty

param($s)$s[$s.Length..0]|%{(1+$i++%2)*"$_"}|%{$r+=$_-9*($_-gt9)}
!($r%10)

Wyjaśnienie

  1. dla każdego znaku ciągu argumentu, w odwrotnej kolejności
  2. uzyskać cyfrę podwójnej wartości cyfry
  3. podwójna wartość cyfry nie może być większa niż 18. Dlatego kumulujemy wartość minus 9, jeśli wartość> 9
  4. zwraca true, jeśli reszta z dzielenia przez 10 wynosi 0

Skrypt testowy

$f = {

param($s)$s[$s.Length..0]|%{(1+$i++%2)*"$_"}|%{$r+=$_-9*($_-gt9)}
!($r%10)

}

@(
    ,("49927398716"      , $True)
    ,("49927398717"      , $False)
    ,("1234567812345670" , $True)
    ,("1234567812345678" , $False)
    ,("79927398710"      , $False)
    ,("79927398711"      , $False)
    ,("79927398712"      , $False)
    ,("79927398713"      , $True)
    ,("79927398714"      , $False)
    ,("79927398715"      , $False)
    ,("79927398716"      , $False)
    ,("79927398717"      , $False)
    ,("79927398718"      , $False)
    ,("79927398719"      , $False)
    ,("374652346956782346957823694857692364857368475368" , $True)
    ,("374652346956782346957823694857692364857387456834" , $False)
    ,("8" , $False)
    ,("0" , $True)
) | % {
    $s, $expected = $_
    $result = &$f $s
    "$($result-eq$expected): $result : $s"
}

Wynik

True: True : 49927398716
True: False : 49927398717
True: True : 1234567812345670
True: False : 1234567812345678
True: False : 79927398710
True: False : 79927398711
True: False : 79927398712
True: True : 79927398713
True: False : 79927398714
True: False : 79927398715
True: False : 79927398716
True: False : 79927398717
True: False : 79927398718
True: False : 79927398719
True: True : 374652346956782346957823694857692364857368475368
True: False : 374652346956782346957823694857692364857387456834
True: False : 8
True: True : 0
mazzy
źródło
2

05AB1E , 12 10 bajtów

RSāÈ>*SOTÖ

Wypróbuj online! lub jako pakiet testowy

Wyjaśnienie

R             # reverse input
 S            # split to list of digits
  ā           # push range[1 ... len(input)]
   È          # map isEven on each
    >         # increment
     *        # multiply doubling every other item
      SO      # sum digits
        TÖ    # mod 10 == 0
Emigna
źródło
1

Haskell: 97

Z jakiegoś powodu to nie działa dla mnie , więc oto moja wersja

l=(\x->(==0)$(`mod`10).sum$zipWith($)(cycle[id,sum.map(read.(:"")).show.(*2)])(map(read.(:""))x))
użytkownik701072
źródło
1

GNU sed, 140 bajtów

(w tym +1 za -rflagę)

s/^(..)*.$/0&/
s/(.)./\1x&/g
s/x[5-9]/1&/g
s/[0x]//g
s/[789]/&6/g
s/[456]/&3/g
s/[369]/&11/g
s/[258]/&1/g
s/.{10}//g
s/.+/false/
s/^$/true/

Sed prawie nigdy nie jest najbardziej naturalnym językiem arytmetyki, ale proszę bardzo:

#!/bin/sed -rf

# zero-pad to even length
s/^(..)*.$/0&/
# double every other digit
s/(.)./\1x&/g
# add carry (converts mod-9 to mod-10)
s/x[5-9]/1&/g
# convert sum to unary
s/[0x]//g
s/[789]/&6/g
s/[456]/&3/g
s/[369]/&11/g
s/[258]/&1/g
# remove whole tens
s/.{10}//g
# output 'true' or false
s/.+/false/
s/^$/true/
Toby Speight
źródło
1

APL, 38 bajtów

d←10∘⊥⍣¯1⋄{0=10|+/+/d x×1+~2|⍳⍴x←⌽d ⍵}

oczekuje liczby jako liczby, a nie ciągu, ale dzieje się tak tylko dlatego, że tryAPL (co zrozumiałe) nie implementuje

jeszcze bardziej redukowalne, jestem pewien ...

Aaron Davies
źródło
1

PHP - 136 znaków

function t($c){foreach($a=str_split(strrev($c)) as $k=>&$v){$v=array_sum(str_split(($k % 2)!==0?2*$v:$v));}return !(array_sum($a)% 10);}
Płomień
źródło
1

MATL , 23 20 bajtów (nie konkuruje)

P!Utn:2X\!*t9>+s10\~

Wypróbuj online!

Wyprowadza 1 dla prawidłowej liczby, w przeciwnym razie 0.

Zaoszczędzono trzy bajty dzięki sugestiom Luisa Mendo.

Wyjaśnienie

P       % flip the order of elements
!       % transpose into column vector
U       % convert char matrix to numeric
t       % duplicate the vector
n       % find the length
:       % create a new vector length n (1, 2, 3, ... n)
2       % number literal
X\      % take it mod 2, to make the new vector (1, 2, 1, ..., (n-1) mod 2 +1)
!       % transpose
*       % element-wise product
t       % duplicate
9       % push 9
>       % 1 if it is greater than 9
+       % add the vectors, this makes the last digit of each the same as the sum of the digits
s       % add them
10      % number literal
\       % mod 10
~       % logical 'not' (element-wise)
        % (implicit) convert to string and display
B. Mehta
źródło
1

Galaretka , 14 bajtów

DUḤJḤ$¦DS$€S⁵ḍ

Wypróbuj online!

Wyjaśnienie:

D              get digits
 U             reverse array
   JḤ$         for every other index,
  Ḥ   ¦        double the value
          €    for each value,
       D $     get the digits
        S$     and sum them
           S   sum the list
            ⁵ḍ check if it's divisible by 10
ellie
źródło
Dlaczego to nie konkuruje?
mudkip201
@ mudkip201 Popraw mnie, jeśli się mylę, ale ta wersja Jelly nie istniała, gdy pytanie zostało zadane, więc nie jest ważne dla pytania.
ellie
3
Jestem całkiem pewien, że istnieje meta konsensus, który mówi, że języki, które powstały po konkursie, nie są już „niekonkurencyjne”
mudkip201