내배캠 Data/Python

[day29] 개인과제 (5번~8번)

경 민 2025. 3. 16. 18:48

① 5번 - 이메일 유효성 검사

1) 문제 요구 조건 

- @ 하나 포함

- @ 전에 하나 이상의 문자

- @ 이후 .을 포함한 문자 2개 이상

 

2) 상식적으로 생각했을 때 유효하지 않을 것 같은 경우

- 도메인명에 . 가 연속으로 나오는 경우, 맨 앞뒤에 오는 경우

- 공백

 

2)번 처리하느라 조금 오래걸렸다.. 

def validate_emails(email_list):
  for email in email_list:
    if ((email.count('@') != 1) | (' ' in email)): #@ 하나 포함, 공백 미포함
      print(f'{email} 유효하지 않은 이메일 주소입니다.')
      continue

    private, domain = email.split('@')
    detail = domain.split('.')    #2)번 조건 확인을 위해 .을 기준으로 나누기

    if ((len(private) >= 1) & ('.' in domain) & all(len(d2) > 0 for d2 in detail) == True):
      print(f'{email} 유효한 이메일 주소입니다.')
      continue
    
    else:
      print(f'{email} 유효하지 않은 이메일 주소입니다.')

 

 

② 6번 - 중복 문자 빈도수 세기

문제 풀이 흐름 ( = 오류 없앤 순서 ^^ )

(우선 감대로(?) 풀어보면서 개념부터 공부하기 위해 쉬운 예제를 만들었다.)

  • 첫 번째 문제 : argument 1개 와야 하는데 2개 왔다는 오류 발생
    • 괄호로 묶어주면서 해결

  • 두 번째 문제 :  알파벳 순서대로~ 중복값 그대로~

 

해결 방법1. 중복 없이 저장할 new list 만들어주기

a = 'heeello'

def solution(string):
  dup_list = []
  dup_list_only = []

  for i in string:
    if ((string.count(i) > 1) & (i not in dup_list_only)):
      dup_list_only.append(i)
      dup_list.append((i, string.count(i)))
  return dup_list
      
result = solution(a)
print(result)

 

해결 방법2. set 활용해서 중복 제거

set
▶ 리스트의 중복을 제거해줌
딕셔너리 형태로 저장됨
... (중요) (밑에 나옴)
a = 'heeello'

def solution(string):
  dup_list = []

  for i in a:
    if (a.count(i) > 1):
      dup_list.append((i, a.count(i)))
  return dup_list
      
result = list(set(solution(a)))
print(result)

 

개념 익혔으니

이제 진짜 문제 풀자!


 

호기롭게 작성했으나

바아로 문제 발생했죠?

  • 문제  :  중복값 없이 처리는 됐는데요. 순서가 엉진망창이에요.
  • 원인 : set은 순서 지키지 않는다. 고로 방법1대로 진행하면 원래 문자열 순서 지키면서 출력된다.
  • 그러나 일반 리스트를 만드는 것보다 set을 만드는 게 속도 측면에서 훨씬 빠르다.
  • 주의할 점 !! : set은 append 매서드 대신 add을 사용해야 한다.
def remove_duplicates_and_count(s):
    result_with_frequency = []
    fornotdup = set()
    
    for i in s:
      if i not in fornotdup:
        fornotdup.add(i)
        result_with_frequency.append((i,s.count(i)))
    return result_with_frequency 


input_string = "abracadabra123321"

result = remove_duplicates_and_count(input_string)
print(result)

 

 

③ 7번 - 유클라이드 거리

방법1. 파이썬 기초 문법

  • 첫 번째 문제 : 반복문 중첩해서 써야한다는 것까지는 생각해냈으나, 두 번째 반복문에서 변수 지정하는 거 생각 못 함.

이거 말이다. 참 쉬운 건데..

문제를 더 많이 풀자.

  • 두 번째 문제 : 결과값을 보니까 마지막에 10.0 으로 출력되는 게 이상해보였다. 나는 10.00 이렇게 다 출력하고 싶은데..
    • 원인 : round는 소수점이 0일 때 하나까지만 출력한다.
    • 해결방법 : distance 뒤에 :.2f 붙여주기
    • 셋째짜리까지 원한다? → .3f , 넷째? → .4f ,.....
def calculate_total_distances(player_positions):
    result = []
    for k,v in player_positions.items():
      distance = 0
      for i in range(len(v)-1):
        x1,y1 = v[i]
        x2,y2 = v[i+1]
        distance += (((x2-x1)**2 + (y2-y1)**2)**0.5)
      result.append(f'{k}의 총 누적 이동 거리: {distance:.2f} 미터')
    return result

player_positions = {
    "John Doe": [(0, 0), (1, 1), (2, 2), (5, 5)],
    "Jane Smith": [(2, 2), (3, 8), (6, 8)],
    "Mike Brown": [(0, 0), (3, 4), (6, 8)]
}

calculate_total_distances(player_positions)

 

 

방법2. math 모듈

  • from math import sqrt"math에서 sqrt만 불러올게" (sqrt : 루트 씌워주는 함수)
from math import sqrt

def calculate_total_distances(player_positions):
    result = []
    for k,v in player_positions.items():
      distance = 0
      for i in range(len(v)-1):
        x1,y1 = v[i]
        x2,y2 = v[i+1]
        distance += sqrt((x2-x1)**2 + (y2-y1)**2)  # 뒤에 **0.5 대신 sqrt하나로 해결!
      result.append(f'{k}의 총 누적 이동 거리: {distance:.2f} 미터')
    return result

player_positions = {
    "John Doe": [(0, 0), (1, 1), (2, 2), (5, 5)],
    "Jane Smith": [(2, 2), (3, 8), (6, 8)],
    "Mike Brown": [(0, 0), (3, 4), (6, 8)]
}

calculate_total_distances(player_positions)

 

 

방법3. numpy

np.linalg.norm(p2 - p1) 
numpy 라이브러리에서 유클리드 거리 구하는 함수 (p2, p1 사이의 직선 거리)
p2 - p1 = 두 좌표의 차이 / np.linalg.norm() = 두 좌표의 차이의 크기 (=거리)
좌표 형식임을 이미 알고 있기 때문에 자동으로 x끼리, y끼리 계산해줌 (훨씬 간단하다!)
  • 주의 : 리스트나 튜플은 np.array 이용해서 넘파이배열로 변환 해줘야 한다.
import numpy as np
result = []
def calculate_total_distances(player_positions):
  for k,v in player_positions.items():
    distance = 0
    for i in range(len(v)-1):
      pre = np.array(v[i])     # 넘파이 배열로 변환
      fol = np.array(v[i+1])   # 넘파이 배열로 변환
      distance += np.linalg.norm(fol-pre)
    result.append(f'{k}의 총 누적 이동 거리: {distance:.2f} 미터')
  return result

player_positions = {
    "John Doe": [(0, 0), (1, 1), (2, 2), (5, 5)],
    "Jane Smith": [(2, 2), (3, 8), (6, 8)],
    "Mike Brown": [(0, 0), (3, 4), (6, 8)]
}

calculate_total_distances(player_positions)

 


④ 8번 - 아라비아 숫자로 치환

방법1. 딕셔너리 2개

korea_num = {'영': 0, '일' : 1, '이' : 2, '삼': 3, '사' : 4, '오' : 5, 
             '육' :6, '칠':7, '팔': 8, '구':9}
english_num = {'zero': 0, 'one' : 1, 'two' : 2, 'three': 3, 'four' : 4, 
               'five' : 5, 'six' :6, 'seven':7, 'eight': 8, 'nine':9}  # 한국어 버전, 영어 버전

def password_decryptor(password_list):
    result = []
    
    for password in password_list:
      kor_count = 0
      eng_count = 0
      rtan_password = password

      for kor, num in korea_num.items():
        kor_count += password.count(kor)
        password = password.replace(kor,str(num))
      for eng, num in english_num.items():
        eng_count += password.count(eng)
        password = password.replace(eng,str(num))

      numeric_password = password
      
      print(f'[{rtan_password}]에 대한 암호는 [{numeric_password}]로, 한글은 [{kor_count}]개, 영어는 [{eng_count}]개 입력되었습니다.')

 

방법2. 딕셔너리 1개

 

count += 1 부분을 count수만큼 더해주는 걸로 바꾸면 안되나? 똑같지 않나?

싶어서 돌려봤는데 같은 답이 나왔다. 

근데도 뭔가 자꾸 찝찝해서

다른 예시 넣어주면서 확인해봤더니

  • 역시나 중복제거하고 카운트를 해주고 있다.
  • 결론 : count += 1로 하면 중복값을 한 번만 처리한다.
  • 해결 : password.count(' ')를 사용해서 중복값에 대해서도 모두 count될 수 있도록 처리
def password_decryptor(password_list):
  numbers = {'0' : ['영','zero'],
               '1' : ['일','one'],
               '2' : ['이','two'],
               '3' : ['삼', 'three'],
               '4' : ['사', 'four'],
               '5' : ['오', 'five'],
               '6' : ['육', 'six'],
               '7' : ['칠', 'seven'],
               '8' : ['팔', 'eight'],
               '9' : ['구', 'nine']}   # [한국어 버전, 영어 버전] 리스트로 묶어주기

  for password in password_list:
    kor_count = 0
    eng_count = 0
    rtan_password = password   #르탄이가 준 패스워드를 rtan_password 변수에 담아둘게

    for numeric, kor_eng in numbers.items():
      if kor_eng[0] in password:   #르탄이가 준 패스워드 뜯어봤을 때 한글이면
        kor_count += password.count(kor_eng[0])
        password = password.replace(kor_eng[0],numeric)
      if kor_eng[1] in password:   #르탄이가 준 패스워드 뜯어봤을 때 영어면
        eng_count += password.count(kor_eng[1])
        password = password.replace(kor_eng[1],numeric)
                                    #조건에 맞춰서 replace된 새로운 password를 
      numeric_password = password   # numeric_password 변수에 담아둘게
                                                
    print(f'[{rtan_password}]에 대한 암호는 [{numeric_password}]로, 한글은 [{kor_count}]개, 영어는 [{eng_count}]개 입력되었습니다.')