CodeWars 19 : VIN Checker

김기욱·2021년 8월 4일
0

코딩테스트

목록 보기
58/68

문제설명

VIN Checker
In this Kata you should write a function to validate VINs, Vehicle Identification Numbers. Valid VINs are exactly 17 characters long, its composed of capital letters (except "I","O" and "Q") and digits. The 9th character is a MODULUS 11 check digit. Here is how it works:

  1. Letters are converted to numbers
    Following the table bellow, letters are converted to numbers. "I","O" and "Q" are invalid characters.
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
1 2 3 4 5 6 7 8   1 2 3 4 5   7   9 2 3 4 5 6 7 8 9
Ex.: VIN 5YJ3E1EA7HF000337 becomes 58135151786000337.
  1. Each number is multiplied by a weight
    The weights are the following: [8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2]
Ex.:
VIN:     5   Y   J   3   E   1   E   A   7   H   F   0   0   0   3   3   7
DECODED: 5   8   1   3   5   1   5   1   7   8   6   0   0   0   3   3   7
WEIGHTS: 8   7   6   5   4   3   2   10  0   9   8   7   6   5   4   3   2
PRODUCT: 40  56  6   15  20  3   10  10  0   72  48  0   0   0   12  9   14
  1. All products are summed up
Ex.:
40+56+6+15+20+3+10+10+0+72+48+0+0+0+12+9+14 = 315
  1. The modulus 11 of the sum is taken
Ex.:
315 mod 11 = 7
  1. Check 9th character
    If the 9th character matches the modulus 11, the VIN is valid.

Ex.:
5YJ3E1EA7HF000337 is a valid VIN, 9th character is 7
Note
If the modulus 11 of the sum is equal to 10, then the digit is "X".

Ex.:
5YJ3E1EAXHF000347 is a valid VIN.
Input Validation
Input validation is part of the Kata, VINs with lenghts different than 17 characters or containing invalid characters should return False as well.

제한사항

None

입출력 예시

"5YJ3E1EA7HF000337" True
"5YJ3E1EAXHF000347" True
"5VGYMVUX7JV764512" True
"7WDMMTDV9TG739741" False
"7JTRH08L5EJ234829" False

풀이

import re
def check_vin(number):
    if len(number) == 17: #길이검사
        is_invalid = re.findall('[^A-HJ-NPR-Z0-9]+', number) #유효문자검사
        if not is_invalid:
            #계산용
            weight = [8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2] 
            #컨버팅용
            num_dic = {'A':1, 'B':2, 'C':3, 'D':4, 'E':5, 'F':6, 'G':7, 'H':8, 
                    'J':1, 'K':2, 'L':3, 'M':4, 'N':5, 'P':7, 'R':9,
                    'S':2, 'T':3, 'U':4, 'V':5, 'W':6, 'X':7, 'Y':8, 'Z':9}
            #해독된 숫자
            decoded_number = list(map(lambda x : num_dic[x] if x.isalpha() else int(x), number))
            # 최종값
            final_num = sum([x*y for x,y in zip(weight, decoded_number)]) % 11
            # 분기처리
            if final_num == 10 and number[8] == 'X':
                return True 
            # 조건엔 없는데 'X'가 오는경우는 final_num이 무조건 10 외에는 안됨
            # (이것때문에 풀이시간 지체 엄청 되었음)
            elif final_num == decoded_number[8] and number[8] != 'X':
                return True
    return False

다른풀이

TRANS = str.maketrans("A B C D E F G H I J K L M N O P Q R S T U V W X Y Z",
                      "1 2 3 4 5 6 7 8   1 2 3 4 5   7   9 2 3 4 5 6 7 8 9")
WEIGHTS = [8,7,6,5,4,3,2,10,0,9,8,7,6,5,4,3,2]

def check_vin(vin):
    try:
        return len(vin) == 17 and vin[8] == "0123456789X"[sum(int(c) * w for c, w in zip(vin.translate(TRANS), WEIGHTS)) % 11]
    except:
        return False

파이써닉하고 간결한 풀이, 그저 아름답네요.
전 언제 이 수준까지 가서 능수능란하게 trans를 떠올리고 try except와 문자열 슬라이싱으로 정리해버릴수 있을런지.. 🤔

profile
어려운 것은 없다, 다만 아직 익숙치않을뿐이다.

0개의 댓글