<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>dosirak_hansol.log</title>
        <link>https://velog.io/</link>
        <description>어?</description>
        <lastBuildDate>Fri, 17 Jan 2025 16:52:23 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>dosirak_hansol.log</title>
            <url>https://velog.velcdn.com/images/dosirak_hansol/profile/36b8e71b-ca7b-405a-83e4-20e49f129d05/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. dosirak_hansol.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/dosirak_hansol" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[실직한 주니어 개발자와 프로젝트 시작, 그리고 nodejs 공부]]></title>
            <link>https://velog.io/@dosirak_hansol/%EC%8B%A4%EC%A7%81%ED%95%9C-%EC%A3%BC%EB%8B%88%EC%96%B4-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%99%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%9C%EC%9E%91-%EA%B7%B8%EB%A6%AC%EA%B3%A0-nodejs-%EA%B3%B5%EB%B6%80</link>
            <guid>https://velog.io/@dosirak_hansol/%EC%8B%A4%EC%A7%81%ED%95%9C-%EC%A3%BC%EB%8B%88%EC%96%B4-%EA%B0%9C%EB%B0%9C%EC%9E%90%EC%99%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%EC%8B%9C%EC%9E%91-%EA%B7%B8%EB%A6%AC%EA%B3%A0-nodejs-%EA%B3%B5%EB%B6%80</guid>
            <pubDate>Fri, 17 Jan 2025 16:52:23 GMT</pubDate>
            <description><![CDATA[<h2 id="실직을-하게-되었다">실직을 하게 되었다.</h2>
<p>사실 지금 말하는게 민망하지만,
작년 8월말에 회사가 갑작스럽게 폐업을 하게되었다.</p>
<p>3년넘게 일했던 멀쩡한 직장 때려치고, 개발자로 취업한지 1년 8개월만에 나에게 이런일이...</p>
<p>작년 남은 한해는 정신 못차리고 지나갔지 않았나 싶다.
공부를 해야하지만서도 실업급여가 나오는 탓에 간절함이 부족했나 싶기도 하고, 아무래도 갑작스러운 상황에 정신 못차렸던 것도 있지 않을까.</p>
<p>이러나 저러나 공부안한건 내 의지가 모자란거지 라고 생각했는데,
아니나 다를까 초반 면접본 몇 곳을 제외하곤 전부 이력서 제출에서 광탈해 버렸다.</p>
<p>개발자 취업이 힘들다곤 하지만, 그동안 너무 회사일만 했었고, 이직준비도 안되어있던 상황이라 그랬던게 컸을까?</p>
<p>정신차리고보니 벌써 25년이 되었고, 만으로 30살이 되어버렸다.</p>
<p>하하하,,,</p>
<p>그러던 와중 갑자기 일이 너무 하고싶어서, 지난주 목요일에 같이 다녔던 직장동료 A에게 전화를 걸었다.</p>
<p>Node.js를 한번 배울겸 미니프로젝트를 하나 하고싶은데, A님이 프론트 작업을 해 주셨으면 좋겠어요. 같이 해보실래요?</p>
<p>A님은 고맙게도 수락하여주셨다.</p>
<p>A님께 먼저 만나 했던말 몇가지를 정리하자면,</p>
<ol>
<li>평일 매일 아침 9시에 만날 것</li>
<li>최대한 실서비스 한다는 생각 하에 프로젝트를 한 번 해보자.</li>
<li>같이 이력서나 면접준비도 하자</li>
</ol>
<p>였고, 벌써 일주일이 지났다.</p>
<p>오랜만에 프로젝트를 하니 학원다닐때가 생각나기도하고, 회사 다닐때가 생각나기도 하고... 기분이 참 묘하더라.</p>
<p>같이 만나서 예전처럼 일하고, 밥먹고, 담배도피고.</p>
<p>새로운 기술을 배우는 것도 좋지만, 일을 다시 하는 기분이 들어서 더 좋은건 아닐런지.</p>
<p>최대한 빨리 프로젝트를 끝내고 싶은 마음이 컸는데, 막상 시작해보니 쉽지만은 않을 것 같다. 확실히 실무를 한번 경험해보고 나서인지는 몰라도, 미니프로젝트 일지라도 많은 고민을 하게 만든다.</p>
<p>아무튼 프로젝트를 하면서도, 내가 이걸 하면 취업하는데 도움이 될까? 하면서 한숨 푹~ 한번 쉬었다가, 에이 안되면 차라리 실서비스 하고 말지 ㅋ 하면서 코드치니 꽤 재밌기도 하다.</p>
<p>회사다닐때 진짜 재밌게 일했는데 ㅎㅎ </p>
<p>많은 사람들이 볼 글은 아닌것같지만, 나와같은 상황에 처한 다른 개발자 분들도 힘내셨으면 좋겠다. </p>
<p>혹시라도 실직 후에 집에만 있게되어서 무기력한 주니어 개발자 분들 중에 같이 프로젝트를 해보고 싶은 분들이 있으시다면 연락 주셨으면 좋겠다.</p>
<p>프로젝트 주요 구성은
Front End : React, Next.js, typescript
Back End : Node.js, Nest.js, typeorm, postgresSQL
등... 이 있다.</p>
<p>아무튼 다들 화이팅 합시다<del>!
박한솔도 화이팅</del>!!!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[FSx 네트워크 드라이브 연결 끊김 현상]]></title>
            <link>https://velog.io/@dosirak_hansol/FSx-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%93%9C%EB%9D%BC%EC%9D%B4%EB%B8%8C-%EC%97%B0%EA%B2%B0-%EB%81%8A%EA%B9%80-%ED%98%84%EC%83%81</link>
            <guid>https://velog.io/@dosirak_hansol/FSx-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC-%EB%93%9C%EB%9D%BC%EC%9D%B4%EB%B8%8C-%EC%97%B0%EA%B2%B0-%EB%81%8A%EA%B9%80-%ED%98%84%EC%83%81</guid>
            <pubDate>Thu, 22 Aug 2024 06:23:38 GMT</pubDate>
            <description><![CDATA[<h2 id="한달에-한번씩-윈도우-서버의-네트워크-드라이브-연결이-끊겼다">한달에 한번씩 윈도우 서버의 네트워크 드라이브 연결이 끊겼다.</h2>
<p>개발서버 뿐만 아니라 실제 운영되고 있는 서버에서도 끊겨서, 꽤나 골치아픈 문제였다.</p>
<p>주말에 나는 늦잠을 자는편이라, 막내인 내가 연결을 못하고 계속해서 팀장님이 토요일 새벽마다 재연결을 하시는 그런 상황이.. 너무 싫었고, 틈 날때마다 찾아보았는데, 해결 지점까지 온듯 했다.</p>
<p>일단 네트워크 드라이브 연결을 30분마다 확인하는 스케줄러가 동작하고있었고, 끊긴 경우에는 개발팀으로 알림톡이 발송되었기에 알림톡 로그를 먼저 확인해보았다.</p>
<h2 id="토요일-새벽-4시-30분에만-끊김">토요일 새벽 4시 30분에만 끊김</h2>
<p>처음에는 이 사실을 알았을땐 당연히 우리 서버 스케줄러중에 4시반에 도는것이 부하가 걸려 이런 일이 생기는 줄 알았으나... 실제로 해당시간대에 동작하는 스케줄러가 없었다.</p>
<p>왜 토요일 특정 시간에만 끊길까...... 에 대해서 계속 생각하고 찾아보다가, 잘 알지도 못하는 AWS FSx 드라이브 설정에 가서 아무거나 눌러보다가 뭔가를 찾게되었다.</p>
<p><img src="https://velog.velcdn.com/images/dosirak_hansol/post/e8c71fc1-7bae-44e1-9835-df37e53df08e/image.png" alt=""></p>
<p>이게웬걸, FSx 주 단위 유지 관리 기간이라는 것이 금요일 19:30 UTC(한국시간 토요일 새벽 4시 30분) 이었다... 웬지 확실치는 않지만 누가봐도 이게 문제라는걸 알수가 있을 것이다.</p>
<p><a href="https://docs.aws.amazon.com/fsx/latest/WindowsGuide/administering-file-systems.html#maintenance-windows">https://docs.aws.amazon.com/fsx/latest/WindowsGuide/administering-file-systems.html#maintenance-windows</a>
AWS 공식문서에 따르면 주 단위 유지 관리기간은 매주 실행되는 것은 아니며, 유지관리 일정이 잡히게되면 설정된 시간에 실행된다고 한다. 이때 네트워크 드라이브 연결은 끊기게 된다고 한다.</p>
<p>더 찾아보았을때 AWS 자체에서 재연결을 할 수 있는 세팅은 없는것같고, 서버에서 직접 재연결을 할 수 있게 하는 배치나 스케줄러를 실행 시키는 것이 최선인것같았다.</p>
<p>아래는 네트워크 드라이브연결 상태 확인 -&gt; 재연결 까지 작업하는 powershell 스크립트 문이다.</p>
<p>우리의 경우 재연결시에 자격증명은 사용하지않아 주석처리 하였고, 대신 DNS 서버를 설정하고 나서 다시 자동으로 변경하는 것 까지 처리하였다.</p>
<p>재연결 후에 호출하는 웹 페이지는 기존에 있었던 알림톡 발송 페이지이다. 해당 페이지에서 다시 네트워크 연결상태를 확인 후에 재연결되었는지, 실패했는지 알림톡을 발송해준다.</p>
<pre><code class="language-bash"># 네트워크 드라이브 문자
$driveLetter = &quot;Z:&quot;

# 네트워크 드라이브 경로
$networkPath = &quot;네트워크드라이브경로&quot;

# 자격 증명
# 자격증명 필요한지 확인 필요
# $username = &quot;your_username&quot;
# $password = &quot;your_password&quot;

# 네트워크 어댑터 이름 가져오기 (이더넷)
$adapterName = Get-NetAdapter | Where-Object {$_.Name -like &quot;Ethernet*&quot;} | Select-Object -ExpandProperty Name

# DNS 서버 IP
$dnsServerIp &quot;DNS 서버 IP&quot;

# 네트워크 드라이브 연결 상태 확인
if (!(Test-Path $driveLetter)) {

    Write-Host &quot;네트워크 드라이브가 연결되지 않았습니다. 다시 연결을 시도합니다...&quot;

    # 기존 연결 해제 (필요한 경우)
    net use $driveLetter /delete

        # 수동 DNS 서버 주소 설정
        Set-DnsClientServerAddress -InterfaceAlias $adapterName -ServerAddresses $dnsServerIp

    # 네트워크 드라이브 재연결
    # 자격증명 필요한지 확인 필요
      # net use $driveLetter $networkPath /user:$username $password
    net use $driveLetter $networkPath

        # DNS 서버 주소 자동으로 받도록 설정
        Set-DnsClientServerAddress -InterfaceAlias $adapterName -ResetServerAddresses

    if (Test-Path $driveLetter) {
        Write-Host &quot;네트워크 드라이브가 성공적으로 다시 연결되었습니다.&quot;
    } else {
        Write-Host &quot;네트워크 드라이브를 다시 연결하는 데 실패했습니다.&quot;
    }

        # 웹 페이지 호출
        Invoke-WebRequest -Uri &quot;호출 할 웹 페이지&quot; -Method Get

} else {
    Write-Host &quot;네트워크 드라이브가 이미 연결되어 있습니다.&quot;
}

# Powershell 종료
exit</code></pre>
<p>로컬에서 테스트 완료해서, 서버에 적용하려 했지만...</p>
<p>사정이 생겨서 적용해보진 못하였다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[자바스크립트 Javascript를 활용한 이미지 확장자 WEBP 형식으로 전환하기]]></title>
            <link>https://velog.io/@dosirak_hansol/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Javascript%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%99%95%EC%9E%A5%EC%9E%90-WEBP-%ED%98%95%EC%8B%9D%EC%9C%BC%EB%A1%9C-%EC%A0%84%ED%99%98%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@dosirak_hansol/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-Javascript%EB%A5%BC-%ED%99%9C%EC%9A%A9%ED%95%9C-%EC%9D%B4%EB%AF%B8%EC%A7%80-%ED%99%95%EC%9E%A5%EC%9E%90-WEBP-%ED%98%95%EC%8B%9D%EC%9C%BC%EB%A1%9C-%EC%A0%84%ED%99%98%ED%95%98%EA%B8%B0</guid>
            <pubDate>Thu, 22 Aug 2024 05:56:45 GMT</pubDate>
            <description><![CDATA[<p>웹페이지에서 사용자의 접근성을 좋게 하는 방법중 하나는
서버에서 처리를 빠르게 하는 방법도 있지만, 이미지 로딩을 최적화 하는 것도 한가지 방법이다.</p>
<p>압축률이 좋은 사진 포맷을 활용하여 사진을 불러오게되면, 용량에 대한 클라이언트측의 부하가 적어지기 때문에, 사진 확장자나 압축방식을 적절하게 활용하는 것이 좋다.</p>
<p>그 중에 요즘 많이 쓰이는 방식이 구글에서 만들어낸 WEBP 확장자를 이용하는 방식인데, 다른 방식으로도 변환이 가능하겠지만, 자바스크립트를 활용하면, 빠른시간안에 적용할 수 있다.</p>
<ul>
<li>주의사항
동적인 gif 파일의 경우엔 해당 방식으로 변환시에 애니메이션은 적용되지 않는다.
아이폰에서 업로드 하는 경우에는 webp형식으로 변환하면 오히려 사진 용량이 늘어나는 현상이 발생한다.</li>
</ul>
<p>주의사항을 참고해서 적용 범위를 살펴보자면, 실제 유저들이 사용하는 부분에서 사용하게되면 예외처리를 해야 하는 부분이 많아보이니, 간단하게 이미지정도만 업로드 하는 부분에 사용하게되면 충분히 유용하게 사용 할 수 있을 것 같다.</p>
<pre><code class="language-javascript">// 해당 함수로 원본 파일 객체(ogFile)를 전달
function convertImgToWebp(ogFile){
    return new Promise(resolve =&gt; {
        let og_src = URL.createObjectURL(ogFile);
        let canvas = document.createElement(&#39;canvas&#39;);
        let ctx = canvas.getContext(&#39;2d&#39;);
        let userImage = new Image();
        userImage.src = og_src;

        userImage.onload = function(){
            //기존 파일과 사이즈 맞춤
            canvas.width = userImage.width;
            canvas.height = userImage.height;
            ctx.drawImage(userImage, 0, 0);

            //webp 로 변경
            let webpImage = canvas.toDataURL(&#39;image/webp&#39;);

            // console.log(webpImage);

            // 변경된 이미지를 다시 파일로 변경 start
            let blobBin = atob(webpImage.split(&#39;,&#39;)[1]);
            let _arr = [];
            for(var i = 0; i &lt; blobBin.length; i++){
                _arr.push(blobBin.charCodeAt(i));
            }
            let webpFile = new File(
                    [new Uint8Array(_arr)], 
                    ogFile.name.split(&#39;.&#39;)[0]+&#39;.webp&#39;,
                    {type: &#39;image/webp&#39;}
                );

            resolve(webpFile);
        }
    })
}</code></pre>
<p>html 엘리먼트인 canvas를 사용해서 복제 후에 확장자 변경과 압축을 진행하는 방식이다.</p>
<p>특징이 있다면 해당 함수를 promise를 리턴한다.
왜냐면.. promise를 사용해서 await을 활용하지 않게되면 해당 함수 내부 로직이 처리되기 전에 호출한 부분 다음을 실행해버리는 경우가 생겨서, await을 사용해서 무조건 리턴 받은 후에 다음 로직을 실행해야한다.</p>
<p>예를들어</p>
<pre><code class="language-javascript">// webp 파일을 리턴 받아야 하는 함수
async function exampleFunction(id) {
  var files = document.getElementById(id).files;


  for( var i=0 ; i&lt; files.length ; i++){
    var _file     = files[i];//webp로 변경전 file
    var file     = null;

    //gif파일은 webp변환 예외
    if(_file.type.indexOf(&#39;gif&#39;) &lt;= 0){
      file = await convertImgToWebp(_file);    //webp로 변경후 file
    } else{
      file = _file;
    }
    //webp 변환시 빈파일로 반환된 경우 원본파일로 업로드처리
    if(Number(file.size) === 0){
      file = _file;
    }

    // ..후처리 로직
  }    
}</code></pre>
<p>이런식으로 async 함수로 선언 후에 await을 사용해서 무조건 webp 변환 함수가 promise를 리턴 후에 이후 로직이 실행되게 해야 한다.</p>
<p>그 외에 gif나 가끔 빈파일로 리턴하는 경우에만 원본 파일로 올리는 예외처리를 해주었다. (사진이 너무 큰 경우에는 DataUrl이 너무 커져서 크롬 자체에서 차단을 하는 것 같다.)</p>
<p>웬만하면 javascript로 하는 방식은 비추하나, 급하게 적용해야 할 부분이 있다면 가장 간단하게 
적용 할 수 있는 유용한 방법이라 생각한다.</p>
<p>해당 방법은 클라이언트 측에서 실행해야 하기 때문에, 유저가 사용하는 부분에서는 지양하는 것이 좋을 것 같다. 예외도 워낙 많아서...</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 코딩테스트, 3진법 뒤집기 (java, StringBuffer, Integer)]]></title>
            <link>https://velog.io/@dosirak_hansol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-3%EC%A7%84%EB%B2%95-%EB%92%A4%EC%A7%91%EA%B8%B0-java-StringBuffer-Integer</link>
            <guid>https://velog.io/@dosirak_hansol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-3%EC%A7%84%EB%B2%95-%EB%92%A4%EC%A7%91%EA%B8%B0-java-StringBuffer-Integer</guid>
            <pubDate>Tue, 22 Nov 2022 08:36:59 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/68935">프로그래머스 3진법 뒤집기 문제</a></p>
<p>level 1에다가 간단한 문제지만, Integer나 StringBuffer에 관한 활용이 없으면 꽤나 돌아갈 것 같은 문제다.</p>
<p>먼저 int 로 받아준 자연수 n 을 String 으로 변환해 준다.</p>
<p>이 때 Integer 안의 toString 메소드를 사용 해 주는데, 괄호 안에 (숫자, 숫자) 형식으로 작성하면 왼쪽의 숫자를 오른쪽 숫자의 진법으로 변환 하여 String으로 변경 해 준다. 
(변환하는 이유는 StringBuffer를 통해 쉽게 뒤집어 주려고)</p>
<pre><code class="language-java">        String str = Integer.toString(n, 3);</code></pre>
<p>그 다음 StringBuffer를 사용하여 문자열을 뒤집어 준다.
이 때 StringBuffer 객체를 만들어서 사용한다.</p>
<pre><code class="language-java">        StringBuffer sb = new StringBuffer(str);
        String reversedStr = sb.reverse().toString();</code></pre>
<p>이러면 일단 3진법으로 변환하여 뒤집는데 까지는 성공.
다시 10진법으로 변환해야 하는데, 방법은 전과 비슷하다.
그런 다음 반환해주면 끝!</p>
<pre><code class="language-java">        int answer = Integer.parseInt(reversedStr,3);
        return answer;</code></pre>
<p>여기까지다.</p>
<p>이 문제에서 나같은 초보자가 배워야 할 것들.</p>
<ul>
<li>Integer 안의 메소드들을 충분히 활용 가능한가.</li>
<li>StringBuffer에 대한 이해도. (사용 하기만 하고 String과 뭐가 다른지에 대해서는 잘 모름)</li>
</ul>
<p>인데 StringBuffer에 대해서는 나중에 따로 공부하여 포스팅 해야겠다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 코딩테스트 2022 KAKAO BLIND RECRUITMENT 신고 결과 받기 [java,중첩반복문]
]]></title>
            <link>https://velog.io/@dosirak_hansol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-2022-KAKAO-BLIND-RECRUITMENT-%EC%8B%A0%EA%B3%A0-%EA%B2%B0%EA%B3%BC-%EB%B0%9B%EA%B8%B0-java%EC%A4%91%EC%B2%A9%EB%B0%98%EB%B3%B5%EB%AC%B8</link>
            <guid>https://velog.io/@dosirak_hansol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-2022-KAKAO-BLIND-RECRUITMENT-%EC%8B%A0%EA%B3%A0-%EA%B2%B0%EA%B3%BC-%EB%B0%9B%EA%B8%B0-java%EC%A4%91%EC%B2%A9%EB%B0%98%EB%B3%B5%EB%AC%B8</guid>
            <pubDate>Thu, 15 Sep 2022 15:27:43 GMT</pubDate>
            <description><![CDATA[<p>저번에 이 문제를 해결 할 때, 중첩반복문에 대한 내용도 모르고있었고, 시간복잡도에 대한 내용도 모르고 있었다.</p>
<p>시간복잡도를 해결하고, HashSet을 이용한 중복제거 처리를 먼저 해주니 코드가 훨씬 간결 해 져서 문제 풀이가 완성되었다.</p>
<h4 id="과거에-작성한-코드">과거에 작성한 코드</h4>
<pre><code class="language-java">
        int[] answer = new int[id_list.length];

        // answer에 넣어줄 값
        HashMap&lt;String, Integer&gt; aCnt = new HashMap&lt;String, Integer&gt;();
        // key : 유저, value : 신고 당한 횟수 
        HashMap&lt;String, Integer&gt; banCnt = new HashMap&lt;String, Integer&gt;();

        // 유저 별 신고 당한 횟수 (초기값 0)
        for(String i : id_list) {
            banCnt.put(i, 0);
            aCnt.put(i, 0);
        }
        // 유저 별 신고 한 유저 담아주기
        for(String b : report) {

            String[] bu = b.split(&quot; &quot;);
            int bc = banCnt.get(bu[1]);

            banCnt.put(bu[1], bc + 1);

        }
        //중복되는지 검사 
        for(int i = 0; i &lt; report.length; i++) {
            int repOvl = -1;
            for(int j = 0; j &lt; report.length; j++) {
                if(report[i].equals(report[j])) {
                    ++repOvl;
                }
            }
            if(i&gt;0) {
                if(i==1) {
                    if(report[i].equals(report[0])) {
                        repOvl = 0;
                    }
                } else {
                    for(int x = 0; x &lt; i; x++) {
                        if(report[i].equals(report[x])) {
                            repOvl = 0;
                        }
                    }
                }
            }
            String[] bu = report[i].split(&quot; &quot;);
            int bc = banCnt.get(bu[1]);
            banCnt.put(bu[1], bc - repOvl);


        }

                //신고당한 회수 k번 이상이면...
        for(int i = 0; i &lt; id_list.length; i++) {
            if(banCnt.get(id_list[i])&gt;=k) {
                for(int j = 0; j &lt; report.length; j++) {
                    if(report[j].split(&quot; &quot;)[1].equals(id_list[i])) {
                        int bcnt = aCnt.get(report[j].split(&quot; &quot;)[0]);

                        if(j&gt;0) {
                            if(j==1) {
                                if(report[j].equals(report[0])) {

                                } else {
                                    aCnt.put(report[j].split(&quot; &quot;)[0], bcnt + 1);
                                }
                            } else {
                                for(int x = 0; x &lt; j; x++) {
                                    if(report[j].equals(report[x])) {

                                    } else {
                                        aCnt.put(report[j].split(&quot; &quot;)[0], bcnt + 1);
                                    }
                                }
                            }
                        } else {
                            aCnt.put(report[j].split(&quot; &quot;)[0], bcnt + 1);
                        }

                    }
                }
            }
        }



        for(int i = 0; i &lt; id_list.length; i++) {
            answer[i] = aCnt.get(id_list[i]);
        }</code></pre>
<p>라는 내용의 말도안되는 코드였는데, 이 다음날 강사님에게 코딩테스트 시간초과가 왜나오는지 여쭤봤고, 일반적으로 중첩반복문 때문인 경우가 많다고 하셔서 그쪽에 집중했고, 코드도 전체적으로 삭제한 다음 다시 생각 해 보기 시작했다</p>
<h4 id="아래가-완성된-코드">아래가 완성된 코드</h4>
<pre><code class="language-java">import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;

class Solution {
    public int[] solution(String[] id_list, String[] report, int k) {
        int[] answer = new int[id_list.length];

        //user 별 신고 당한 횟수
        HashMap&lt;String,Integer&gt; banCnt = new HashMap&lt;String,Integer&gt;();
        //answer에 넣어 줄 값
        HashMap&lt;String,Integer&gt; aCnt = new HashMap&lt;String,Integer&gt;();

        //user 별 신고 당한 횟수, answer에 넣어 줄 값 Mapping 처리 (초기값 0)
        for(String il : id_list) {
            banCnt.put(il, 0);
            aCnt.put(il, 0);
        }

        //report 에서 중복 제거 작업을 먼저 해준다면?
        HashSet hashSet = new HashSet();
        for(String rp : report) {hashSet.add(rp);}
        ArrayList&lt;String&gt; dor = new ArrayList&lt;&gt;(hashSet);

        for(String d : dor) {
            String bun = d.split(&quot; &quot;)[1];
            int cnt = banCnt.get(bun);
            banCnt.put(bun, cnt + 1);
        }

        for(String d : dor) {
            if(banCnt.get(d.split(&quot; &quot;)[1]) &gt;= k) {
                aCnt.replace(d.split(&quot; &quot;)[0], aCnt.get(d.split(&quot; &quot;)[0])+1);
            }
        }

        for(int i = 0; i &lt; id_list.length; i++) {
            answer[i] = aCnt.get(id_list[i]);
        }

        return answer;
    }
}</code></pre>
<p>이때 정말 약간 크게 배운 것 같았다.</p>
<ol>
<li>일단 내가 쓴 코드를 내가 직접 보고서 문제점을 발견 한 다는게 상당히 어렵다는 것...</li>
<li>생각보다 쓸데없이 사용된 코드들이 많다는 점.</li>
<li>여러가지 배운 기능 들 중 내가 제대로 사용 가능 한 코드는 아직 적다.</li>
</ol>
<p>열심히 공부해야지.</p>
<h2 id="한솔-깃허브"><a href="https://github.com/dosirakHansol">한솔 깃허브</a></h2>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로그래머스 코딩테스트 연습 2021 KAKAO BLIND RECRUITMENT 신규 아이디 추천 [java, 정규식]]]></title>
            <link>https://velog.io/@dosirak_hansol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%97%B0%EC%8A%B5-2021-KAKAO-BLIND-RECRUITMENT-%EC%8B%A0%EA%B7%9C-%EC%95%84%EC%9D%B4%EB%94%94-%EC%B6%94%EC%B2%9C-java-%EC%A0%95%EA%B7%9C%EC%8B%9D</link>
            <guid>https://velog.io/@dosirak_hansol/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EC%BD%94%EB%94%A9%ED%85%8C%EC%8A%A4%ED%8A%B8-%EC%97%B0%EC%8A%B5-2021-KAKAO-BLIND-RECRUITMENT-%EC%8B%A0%EA%B7%9C-%EC%95%84%EC%9D%B4%EB%94%94-%EC%B6%94%EC%B2%9C-java-%EC%A0%95%EA%B7%9C%EC%8B%9D</guid>
            <pubDate>Thu, 15 Sep 2022 15:13:55 GMT</pubDate>
            <description><![CDATA[<p>오늘 풀은 문제는 &quot;정규식&quot;에 관한 부분이었다.</p>
<p>주요 사용된 메소드들은
String에 관련된 replace, replaceAll, charAt 이 있다.</p>
<p>오늘 문제는 정규식에 관한 부분이 대다수여서 크게 오래 걸리거나 하진 않았지만,
정규식은 머리에 외우고 다니지도 않고, 많이 써보지도 않아서인지 구글링을 좀 했다 ㅎ</p>
<pre><code class="language-java">    new_id = new_id.toLowerCase();</code></pre>
<p>첫번째로 아이디 입력값에 만약 대문자가 있을 경우에 소문자로 치환해주는 toLowerCase 메소드를 사용해준다.</p>
<pre><code class="language-java">    new_id = new_id.replaceAll(&quot;[^a-z0-9-_.]&quot;, &quot;&quot;);입력하세요</code></pre>
<p>그 다음으론 replaceAll을 이용해, 해당 id 안에는 알파벳, 숫자, -, _, . 만 들어가야 함으로
정규식을 이용해서 그외의 문자열들을 공백으로 만들어준다.</p>
<p>여기서 문자열 치환 메소드는 보통 2개인데
replace 와 reaplceAll 이 있다.</p>
<p>이 두 메소드의 차이점은 매개변수에 있는데,</p>
<pre><code class="language-java">      String replace(CharSequnce target, CharSequence replacement)
      String replaceAll(String regex, String replacement)</code></pre>
<p>replace 는 일반 문자열을 찾아서 치환해주고,
replaceAll 은 정규식형태의 String 값을 넣어준다.
(CharSequence 는 String을 포괄하는 인터페이스)</p>
<p>아무튼 다음 코드 설명으로 넘어가면</p>
<pre><code class="language-java">      while(new_id.contains(&quot;..&quot;)) {new_id = new_id.replace(&quot;..&quot;, &quot;.&quot;);}</code></pre>
<p>이번엔 굳이 replaceAll을 사용하진 않았다.
정규식을 안쓸거니깐!!</p>
<p>.. 을 . 으로 바꿔주는 형태인데,
... 인 경우는 한번밖에 치환을 안해줘서 남는 경우가 있으니
.. 이 없어질때 까지 반복문을 돌려주는 형태로 작성했다.</p>
<p>어.. 근데 이거 글쓰면서 생각난건데, CharSequence가 String을 상속하는 인터페이스라면, replace에서도 replaceAlㅣ에서 사용하는 정규식을 사용 할 수 있어야 하는거 아닌가?
하고 사용해 봤는데... 뭔가 제대로 되지 않는다. 
내 생각이 틀린건가? 하고 생각이 들어서 찾아봤는데,
그게아니고 그냥 String 안에 있는 toString 메소드가 오버라이딩 되어있는 형태인것같다...</p>
<p>아 진짜 인터페이스는 아직도 잘 모르겠다 ㅎ 이해가 갈랑말랑...</p>
<p>아무튼 다음으로.</p>
<pre><code class="language-java">        new_id = new_id.replaceAll(&quot;^[.]*&quot;, &quot;&quot;);
        new_id = new_id.replaceAll(&quot;[.]$&quot;, &quot;&quot;);</code></pre>
<p>아이디의 처음과 마지막에 . 이 들어가지 않도록 지워주는 작업이다.</p>
<p>흠.. 이것도 한줄로 바꾸는거 가능할거같은데, 조금 더 공부 해 봐야지.</p>
<pre><code class="language-java">        if(&quot;&quot;.equals(new_id)) new_id = &quot;a&quot;;</code></pre>
<p>만약에 아이디가 빈 문자열로 들어오게 되는경우엔, a 한글자를 할당해준다.</p>
<pre><code class="language-java">        if(new_id.length() &gt; 15) new_id = new_id.substring(0, 15);</code></pre>
<p>아이디가 15글자를 넘어 갈 경우엔 15자리 까지만 끊어준다.</p>
<pre><code class="language-java">        new_id = new_id.replaceAll(&quot;[.]$&quot;, &quot;&quot;);</code></pre>
<p>만약에 15자리 까지 끊어줬는데, . 이 마지막에 올 경우가 있을수도 있으니 한번 더 제거 해 준다.</p>
<pre><code class="language-java">        if(new_id.length() &lt; 3) {
            char lastC = new_id.charAt(new_id.length()-1);
            while(new_id.length() &lt; 3) {new_id = new_id + lastC;}
        }</code></pre>
<p>그리고 마지막으로 3자리 이하 일 때
마지막 char를 사용해서 3자리가 될때 까지 id 에 추가 해 주도록 한다.</p>
<p>이렇게 하면 끝!</p>
<p>다른 분들의 문제 풀이도 한번 봤는데, 재사용성을 생각하고 푸신 분의 풀이를 보니
아.. 이게 자바의 장점인데도 난 왜 문제 푸는데 급급 할까 ㅎㅎ 란 생각이 들더라...</p>
<p>다음 부턴 재사용성도 한번 생각을 해보고 접근 하는게 좋을듯 하다.</p>
<p>예를들면, 위와같이 1~7 단계를 거쳐서 사용 되는 경우에는 각각 메소드들을 만들어 놓고 사용하는것이 유지보수 측면이나 가독성 면에서도 훨씬 좋아지는 느낌이 들었다.</p>
<p>아무튼 완성된 코드는 아래와 같다.</p>
<pre><code class="language-java">    public String solution(String new_id) {

        new_id = new_id.toLowerCase();
        new_id = new_id.replaceAll(&quot;[^a-z0-9-_.]&quot;, &quot;&quot;);
        while(new_id.contains(&quot;..&quot;)) {new_id = new_id.replace(&quot;..&quot;, &quot;.&quot;);}
        new_id = new_id.replaceAll(&quot;^[.]&quot;, &quot;&quot;);
        new_id = new_id.replaceAll(&quot;[.]$&quot;, &quot;&quot;);
        if(&quot;&quot;.equals(new_id)) new_id = &quot;a&quot;;
        if(new_id.length() &gt; 15) new_id = new_id.substring(0, 15);
        new_id = new_id.replaceAll(&quot;[.]$&quot;, &quot;&quot;);
        if(new_id.length() &lt; 3) {
            char lastC = new_id.charAt(new_id.length()-1);
            while(new_id.length() &lt; 3) {new_id = new_id + lastC;}
        }


        String answer = new_id;
        return answer;
    }</code></pre>
<p><a href="https://github.com/dosirakHansol">https://github.com/dosirakHansol</a></p>
]]></description>
        </item>
    </channel>
</rss>