https://school.programmers.co.kr/learn/courses/30/lessons/72410
해당 문제는 결국 규칙에 맞는 아이디를 추천하는 것이다.
아이디 규칙은 다음과 같다.
아이디의 제한 사항은 다음과 같다.
string solution(string new_id) {
string answer = "";
// 소문자 치환
// 레퍼런스는 포인터를 쓰는 것과 같음.
for (char& ch : new_id) {
ch = tolower(ch);
}
// 숫자, 빼기, 밑줄, 마침표
for (char ch : new_id) {
if (isdigit(ch) ||
isalpha(ch) ||
// ch가 "-_." 중 하나인지 확인하는 조건문
strchr("-_.", ch)) {
answer += ch;
}
}
int idx = -1;
// "answer" 문자열에서 연속된 마침표("..")를 하나의 마침표(".")로 바꾸는 반복문
while ((idx = answer.find("..")) != -1) { // answer 문자열에서 ".."을 찾고, 찾은 위치를 idx에 저장 (없으면 -1 반환)
answer.replace(idx, 2, "."); // idx 위치에서 2개의 문자("..")를 "."으로 대체
}
// .가 처음이나 끝에 위치할 경우
if (answer.front() == '.') answer = answer.substr(1);
if (answer.back() == '.') answer = answer.substr(0, answer.length() - 1);
// 빈 문자열이라면? a 대입
if (answer.empty())
answer += "a";
// 길이가 16자 이상이라면?
if (answer.size() >= 16) {
answer = answer.substr(0, 15);
// 마지막의 문자가 . 이라는 경우의 예외처리
if (answer.back() == '.')
answer.pop_back();
}
// 길이가 두 자 이하라면?
while(answer.size() < 3)
answer += answer.back();
return answer;
}
내가 풀이한 코드의 성능
다 푼 뒤에
훑어보다가 발견한 다른 사람의 코드
참고할 만 하다.
가독성이 좋다.
#include <bits/stdc++.h>
using namespace std;
string solution(string new_id) {
for (char& ch : new_id) if ('A' <= ch && ch <= 'Z') ch |= 32;
string ret;
for (char& ch: new_id) {
if ('a' <= ch && ch <= 'z'
||
'0' <= ch && ch <= '9'
||
strchr("-_.", ch)) ret += ch;
}
new_id = ret;
ret.clear();
for (char& ch: new_id) {
if (!ret.empty() && ret.back() == '.' && ch == '.') continue;
ret += ch;
}
if (ret.front() == '.') ret.erase(ret.begin());
if (ret.back() == '.') ret.pop_back();
if (ret.empty()) ret = "a";
if (ret.size() >= 16) ret = ret.substr(0, 15);
if (ret.back() == '.') ret.pop_back();
while (ret.size() <= 2) ret += ret.back();
return ret;
}
해당 코드의 성능
추가
정규표현식을 사용 풀이
string solution(string new_id) {
string answer = "";
// 1단계: 모든 문자를 소문자로 변환
for (char& ch : new_id) {
ch = tolower(ch);
}
// 2단계: 소문자, 숫자, 빼기, 밑줄, 마침표 제외한 모든 문자 제거
answer = regex_replace(new_id, regex("[^a-z0-9-_.]"), "");
// 3단계: 마침표가 2번 이상 연속된 부분을 하나의 마침표로 변환
answer = regex_replace(answer, regex("\\.+"), ".");
// 4단계: 문자열 처음이나 끝에 있는 마침표 제거
answer = regex_replace(answer, regex("^[.]|[.]$"), "");
// 5단계: 빈 문자열이라면 "a" 대입
if (answer.empty())
answer = "a";
// 6단계: 길이가 16자 이상이면 첫 15개 문자만 남기고, 끝에 마침표가 있다면 제거
if (answer.size() > 15) {
answer = answer.substr(0, 15);
answer = regex_replace(answer, regex("[.]$"), "");
}
// 7단계: 길이가 2자 이하라면 길이가 3이 될 때까지 마지막 문자 반복
while (answer.size() < 3)
answer += answer.back();
return answer;
}
정규 표헌식 성능
각 regex_replace 설명
- regex_replace(new_id, regex("[^a-z0-9-_.]"), "")
- 정규 표현식 [^a-z0-9-_.]은
소문자 알파벳, 숫자, 하이픈(-), 밑줄(_), 마침표(.)를 제외한 모든 문자를 의미. - 이 부분을 빈 문자열 ""로 대체하여 제거.
- 정규 표현식 [^a-z0-9-_.]은
- regex_replace(answer, regex("\\.+"), ".")
- 정규 표현식 \\.+는 하나 이상의 마침표 .를 의미.
- 연속된 마침표들을 하나의 마침표로 변환.
- regex_replace(answer, regex("^[.]|[.]$"), "")
- 정규 표현식 ^[.]|[.]$는 문자열 시작 또는 끝에 있는 마침표 .를 의미.
- 문자열의 처음이나 끝에 위치한 마침표를 제거.
- regex_replace(answer, regex("[.]$"), "")
- 이 부분은 answer.substr(0, 15)
이후 문자열 끝에 남아 있는 마침표를 제거하기 위해,
정규 표현식 [.]$를 사용해 끝에 위치한 마침표를 찾아서 제거.
- 이 부분은 answer.substr(0, 15)
정규 표현식을 사용하면 여러 문자나 패턴을 간결하게 처리할 수 있어서 이 문제에 유용하다.
성능 차이
정규표현식 > 남의 코드 > 첫제출 코드
코딩테스트를 풀기 위해
정규표현식을 알아두면 좋을 것 같다.
'콘솔창 & 윈도우창 > 코딩 테스트' 카테고리의 다른 글
프로그래머스 LV.2 기능개발 (1) | 2024.11.14 |
---|---|
프로그래머스 LV.2 더 맵게 (0) | 2024.11.13 |
프로그래머스 LV.2 짝지어 제거 (0) | 2024.11.12 |
프로그래머스 LV.2 의상 (2) | 2024.11.11 |
프로그래머스 LV.2 영어 끝말잇기 (1) | 2024.11.11 |