오픈채팅방

NJW·2022년 4월 17일
0

코테

목록 보기
36/170

들어가는 말

2019 카카오 블라인드 1차 코테에서 나왔던 문제다. 이번에도 문자열 파싱에 관한 문제다. 오픈 채팅방에 나올 안내 메세지를 리턴하는 거다. 이때 중요한 건 유저의 닉네임이다. 닉네임 변경에는 두 가지가 있는데, 하나는 채팅방을 나갔다 오는 것이고 또 다른 하나는 채팅방 내에서 닉네임을 바꾸는 것이다. 이때 닉네임은 중복이 가능하다.

보는 순간 map을 쓰면 좋겠다고 생각했다. map의 key는 중복이 되지 않으니까 id를 key에 넣고 닉네임이 바뀔 때마다 해당 id에다가 바뀐 닉네임을 value로 넣으면 되는 거 아닌가. 하지만, 여기서 약간의 문제가 생겼으니 바로 이중 for문을 두 번이나 돌려야 한다는 거다. id와 name을 저장한 이중 for문, 실제로 메시지를 저장하는 이중 for문.

그러나, 이보다 더 큰 고민이 있었으니... 바로 문자열 파싱이다. 유저가 enter, leave, change하는 알림은 문장으로 되어 있기 때문에 총 세 가지 요소로 나눠야 했다. 유저의 행동, 유저의 id, 유저의 닉네임. 분명 우아한 방벙이 있었을 테지만(stringstream이라든가...), 나는 직접 빈칸의 위치를 찾아 substr()을 이용하는 방법을 사용했다. 그 결과 풀었다. 물론 우아함은 살짝 떨어질지 몰라도...

코드 설명

먼저 map을 이용해 id와 name을 받아야 했다. 이중 for문을 사용해 첫 for문에는 문장 하나를 두 번재 for문에는 문장의 문자를 하나씩 검사하도록 했다. 그리하여 빈칸이 나오면 blank에 ++해주는 것으로 빈칸 앞뒤의 위치를 알았냈다. blank가 1이면 앞에는 행동이, 뒤에는 id가 있다는 뜻이고 blank가 2이면 앞에는 id가, 뒤에는 name이 있다는 뜻이다.
다음 행동이 "Leave"가 아닐 경우에만 문자열을 나눠 map에 넣어줬다("Leave"인 경우에는 빈칸이 하나밖에 없기 때문에 문제가 생긴다). id_l은 id의 길이를 name_l은 name의 길이를 나타낸다(여기서 1을 하나 더 빼줘야 정확한 길이가 나온다). id를 first부터 id_l-1 길이까지 넣고 name을 second부터 name_l 길이까지 넣는다. 다음 만들어 놓은 map인 id_name에 id를 key로 name을 value로 넣는다. 이렇게 하면 닉네임이 바뀌었다 하더라도 자동으로 수정이 된다. map의 key는 중복된 값이 들어올 수 없기 때문이다.

다음은 메세지를 answer에 넣는 작업이다. blank를 찾는 방법은 위의 이중for문과 동일하게 해주면 된다. 그리고 행동이 "Enter"일 경우에는 id를 id_name에서 찾아서 존재할 경우 tmp에다가 해당 value인 name을 더하고 뒷 문장을 더하면 된다. 그리고 만들어진 tmp를 answer에 넣으면 된다. "Leave" 또한 마찬가지다. 다만, "Leave"에서 id의 길이는 r.length() - first다. 왜냐하면 "Leave"는 빈칸이 하나밖에 없기 때문이다. 동일하게 id가 존재한다면 해당하는 id의 value를 tmp에 추가하고 필요한 문장을 추가한다. 그리고 answer에 push하면 "Leave"도 완성이다.

마지막으로 만들어진 answer를 리턴하면 진짜 끝! 휴... 구구절절하다. 꼭 stringstream을 익혀서 더 우아한 코드를 짜야겠다.

코드

#include <string>
#include <vector>
#include <map>
#include <iostream>

using namespace std;

vector<string> solution(vector<string> record) {
    vector<string> answer;
    map<string, string> id_name;
    
    for(auto r : record){
        int blank = 0;
        int first = 0;
        int second = 0;
        
        for(int i=0; i<r.length(); i++){
            if(r[i] == ' '){
                blank++;
                if(blank == 1){
                    first = i+1;
                }
                if(blank == 2){
                    second = i+1;
                }
            }
        }           
            if(r.substr(0, first-1) != "Leave"){
                int id_l = second - first;
                int name_l = r.length() - second;
                string id = r.substr(first, id_l-1);
                string name = r.substr(second, name_l);
                id_name[id] = name;
            }
    }
    
    for(auto r : record){
        int blank = 0;
        int first = 0;
        int second = 0;
        string tmp = "";
        
        for(int i=0; i<r.length(); i++){
            if(r[i] == ' '){
                blank++;
                if(blank == 1){
                    first = i+1;
                }
                if(blank == 2){
                    second = i+1;
                }
            }
        }
        if(r.substr(0, first-1) == "Enter"){
            int id_l = second - first;
            string id = r.substr(first, id_l-1);
            auto name = id_name.find(id);
            if(name != id_name.end()){
                tmp += name->second;
            }
            tmp += "님이 들어왔습니다.";
            answer.push_back(tmp);
        }
        
        if(r.substr(0, first-1) == "Leave"){
            int id_l = r.length() - first;
            string id = r.substr(first, id_l);
            auto name = id_name.find(id);
            if(name != id_name.end()){
                tmp += name->second;
            }
            tmp += "님이 나갔습니다.";
            answer.push_back(tmp);
        }
    }

    return answer;
}
profile
https://jiwonna52.tistory.com/

0개의 댓글