<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>ice rabbit programming</title>
    <link>https://icerabbit.tistory.com/</link>
    <description>NC SOFT Software Programmer</description>
    <language>ko</language>
    <pubDate>Sun, 10 May 2026 03:31:54 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>판교토끼</managingEditor>
    <image>
      <title>ice rabbit programming</title>
      <url>https://tistory1.daumcdn.net/tistory/3831415/attach/3d73938419634bafaa1f6870944b7449</url>
      <link>https://icerabbit.tistory.com</link>
    </image>
    <item>
      <title>[C++] GoF 패턴 간단 정리(1) - 공통성과 가변성의 분리, 재귀적 포함</title>
      <link>https://icerabbit.tistory.com/166</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;지난 &lt;a href=&quot;https://icerabbit.tistory.com/165&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;정규표현식 간단 정리 글&lt;/a&gt;에 이어서 이번에는 디자인 패턴에 관해 강의를 들으며 정리했던 필기를 정리하려고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;약 4년 반 전에 포스팅했던 &lt;a href=&quot;https://icerabbit.tistory.com/83&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;Typescript 강의를 듣고 정리했던 글&lt;/a&gt;과 비슷하겠네요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어느새 처음 입사한지 만 5년이 흐른 지금, 기존 코드도 나름 많이 읽었고 선배 및 동료 개발자들과 리뷰를 하면서 더 나은 코드를 작성할 수 있도록 노력해오기도 했습니다. (개인적으로는 아직 많이 부족하다고 생각합니다만...)&lt;br /&gt;C#, 파이썬과 Typescript를 거쳐서 현재는 C++을 주로 사용하고 있어서 GoF 패턴을 C++ 강좌로 접할 기회가 있어 듣고 간략하게 정리한 내용입니다.&lt;br /&gt;대부분 한 번씩 사용해봤을 법한 패턴들입니다. 다만 패턴에 너무 매몰되지 않고 생산성과 현재 프로덕트가 처한 상황에 맞게 적용하면 된다고 생각하고 있습니다. 여러 가지가 중요하긴 하지만 저는 개인적으로는 &amp;lt;코드 중복의 방지&amp;gt;와 &amp;lt;함수와 클래스의 명확함(한 번에 하나의 일)&amp;gt;이 가장 근본적이고, 이후에 필요에 맞게 쌓아 올려지는 것이 아닌가 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨌거나 약 세 편에 나뉘어서 이전에 썼던 필기들을 올려볼까 합니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;h1&gt;들어가기 전에&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Protected&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Protected &lt;/span&gt;생성자&lt;span&gt;: &lt;/span&gt;상속받은 자식 클래스로만 인스턴스 생성 가능&lt;span&gt;(&lt;/span&gt;부모 클래스 인스턴스 직접 생성 불가&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Protected &lt;/span&gt;소멸자&lt;span&gt;: &lt;/span&gt;객체를 스택에 만들 수 없게 할 때&lt;span&gt;(&lt;/span&gt;즉&lt;span&gt;, Heap&lt;/span&gt;에만 만들게&lt;span&gt;) &lt;/span&gt;사용한다&lt;span&gt;. &lt;/span&gt;참조 계수 기반의 객체 수명 관리 기법에서 주로 사용한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;가상 함수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상 함수로 만들지 않고 부모 타입 포인터에 자식 객체를 넣을 경우 오버라이딩 되지 않음&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가상함수에&lt;span&gt; =0&lt;/span&gt;을 붙이면 순수 가상 함수가 된다&lt;span&gt;. &lt;/span&gt;구현부가 없고 구현 클래스에서 오버라이딩이 필수이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상 클래스&lt;span&gt;: &lt;/span&gt;순수 가상함수를 한 개 이상 가지고 있다&lt;span&gt;. &lt;/span&gt;인스턴스를 생성할 수 없고&lt;span&gt;, &lt;/span&gt;포인터 변수는 생성할 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;공통성과 가변성의 분리&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변하지 않는 전체 흐름 내에 있는 변하는 부분을 분리하여&lt;span&gt;, &lt;/span&gt;정책이 변경되었을 때 코드의 수정을 최소화 하도록 한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;개방 폐쇄의 법칙&lt;span&gt;(OCP: Open Close Principle)&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;기능 확장&lt;span&gt;(&lt;/span&gt;모듈&lt;span&gt;, &lt;/span&gt;클래스&lt;span&gt;, &lt;/span&gt;함수 추가&lt;span&gt;)&lt;/span&gt;에 열려 있고 수정&lt;span&gt;(&lt;/span&gt;기존 코드 수정&lt;span&gt;)&lt;/span&gt;에는 닫혀 있어야 한다는 원칙&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;새로운 클래스가 추가되어도 기존 클래스의 코드를 수정하지 않도록 만들어야 한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Template Method &lt;/span&gt;패턴 &lt;span&gt;&amp;ndash; &lt;/span&gt;가상 함수로 분리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상속 기반 패턴&lt;span&gt;. &lt;/span&gt;전체 흐름 중 변하는 부분을 가상 함수로 정의한다&lt;span&gt;. &lt;/span&gt;즉&lt;span&gt;, &lt;/span&gt;해당 부분의 변경이 필요하면 파생 클래스를 새로 만들어서 적용한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;컴파일 타임에 정책을 정해야 한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;파생 클래스에서 오버라이딩하므로 해당 클래스에서만 접근이 가능하다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;참고로&lt;span&gt; final &lt;/span&gt;키워드를 붙이면 파생 클래스에서 원 함수를 변경할 수 없다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Strategy &lt;/span&gt;패턴 &lt;span&gt;&amp;ndash; &lt;/span&gt;인스턴스로 교체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;변하는 것을 인터페이스&lt;span&gt;(&lt;/span&gt;약한 결합&lt;span&gt;)&lt;/span&gt;로 설계하여 별도의 클래스로 정의한다&lt;span&gt;. &lt;/span&gt;즉&lt;span&gt;, &lt;/span&gt;해당 부분의 변경이 필요하면 인터페이스를 구현하는 클래스를 만들어서 적용한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;런타임에 정책을 정하므로 실행 시간에도 변경 적용할 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;가상 함수 기반이므로 상대적으로 느리다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;별개의 클래스이므로 전혀 다른 클래스에서도 정책을 같이 사용할 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Policy Base Design(&lt;/span&gt;단위 전략 디자인&lt;span&gt;) &amp;ndash; &lt;/span&gt;템플릿 인자로 교체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Template &lt;/span&gt;인자를 사용하여 정책 클래스를 교체하는 기법이다&lt;span&gt;. GoF &lt;/span&gt;패턴에 있지는 않으나&lt;span&gt; C++&lt;/span&gt;에서 널리 사용되는 전략이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&amp;lt;typename ThreadModel&amp;gt;&lt;/span&gt;과 같이 사용하여&lt;span&gt;, template &lt;/span&gt;인자로 사용되는 클래스를 바꿀 수 있도록 한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;함수 내에 변하는 것과 변하지 않는 것이 혼재해 있을 경우에도 사용이 가능하다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Strategy(&lt;/span&gt;전략&lt;span&gt;) &lt;/span&gt;패턴과 비교했을 때&lt;span&gt; inline &lt;/span&gt;함수를 사용하므로 실행 속도가 조금 더 빠르지만&lt;span&gt;, &lt;/span&gt;컴파일 타임에 정책을 정해야 한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Application Framework&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Main &lt;/span&gt;함수에 전체적인 흐름을 담아서 라이브러리 내부에 감추는 방식이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;모든 것을 객체로 한다&lt;span&gt;. (&lt;/span&gt;단&lt;span&gt;, C++&lt;/span&gt;은&lt;span&gt; Main&lt;/span&gt;은 무조건 일반 함수&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;특정 분야의 프로그램은 전체적 흐름이 항상 유사하다&lt;span&gt;. (GUI, &lt;/span&gt;게임 등&lt;span&gt;)&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737462111414&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CWinApp* g_app = 0;
int main() {
  if (g_app-&amp;gt;InitInstance() == true)
    g_app-&amp;gt;Run();
  g_app-&amp;gt;ExitInstance();
}

// 프로그램 전체 흐름 프레임워크
class CWinApp {
    public:
     CWinApp() { g_app = this; } // 전역 객체에 어플리케이션 정보 저장
     virtual bool InitInstance(() { return false; }
     virtual bool Run() { return false; }
     virtual Int ExitInstance() { return 0; }
)
// 파생 클래스
class MyApp : public CWinApp {
    public:
     virtual bool InitInstance { &amp;hellip; }
     virtual int ExitInstance() { &amp;hellip; }
}
MyApp theApp; // 전역 객체 생성자가 main보다 먼저 실행된다.&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;프레임워크 정의하는 추상 클래스가 있고 사용자는 그 틀에 맞춰서 파생 클래스를 만든다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;MFC, QT, WxWidget, iOS, Android &lt;/span&gt;등에서 사용하는 형태이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;일반 함수와 가변성 &lt;span&gt;&amp;ndash; &lt;/span&gt;함수 인자화&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정책이 변경될 경우 라이브러리나 일반 함수 내부를 수정하지 않아도 되도록 설계하는 것이 필요하다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;멤버 함수가 변할 경우&lt;span&gt;: &lt;/span&gt;가상 함수나&lt;span&gt; strategy &lt;/span&gt;패턴을 사용할 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;일반 함수의 경우&lt;span&gt;: &lt;/span&gt;변해야 하는 것&lt;span&gt;(&lt;/span&gt;정책&lt;span&gt;)&lt;/span&gt;을 함수 인자화한다&lt;span&gt;.&lt;br /&gt;&lt;/span&gt;함수 포인터 &lt;span&gt;&amp;ndash; &lt;/span&gt;코드 메모리가 증가하지 않지만 인라인 치환 불가&lt;span&gt;&lt;br /&gt;&lt;/span&gt;함수 객체&lt;span&gt;, &lt;/span&gt;람다 표현식 &lt;span&gt;&amp;ndash; &lt;/span&gt;인라인 치환이 되지만 코드 메모리가 증가&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;State &lt;/span&gt;패턴&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상태에 따라 다른 행동을 해야 할 때 구현할 수 있는 방법이다&lt;span&gt;. &lt;/span&gt;아래는 각 기법의 비교이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;분기&lt;span&gt;: &lt;/span&gt;여러 함수에 조건에 따른 분기가 들어갈 경우&lt;span&gt;, &lt;/span&gt;모든 동작 함수에 분기가 필요하고 새 조건 추가 시 모든 곳에 분기가 추가되는 문제가 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;가상 함수&lt;span&gt;: &lt;/span&gt;처리는 되나 새 인스턴스를 사용한 것으로 처리된다&lt;span&gt;. &lt;/span&gt;즉&lt;span&gt;, &lt;/span&gt;객체의 변화가 아니라 새 인스턴스가 생성된 것이므로 클래스에 의한 변화이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;State &lt;/span&gt;패턴&lt;span&gt;: &lt;/span&gt;변경되는 동작들을 다른 클래스로 분리&lt;span&gt;(&lt;/span&gt;인터페이스 정의&lt;span&gt;)&lt;/span&gt;한다&lt;span&gt;. &lt;/span&gt;즉&lt;span&gt;, &lt;/span&gt;객체의 속성은 유지하면서 동작을 변경할 수 있다&lt;span&gt;. Strategy &lt;/span&gt;패턴과 유사하다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1737462125679&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;struct IState {
  virtual void run() = 0;
  virtual void attack() = 0;
  virtual ~IState() {}
};

class NormalState : public IState { &amp;hellip; }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;span&gt;State &lt;/span&gt;패턴은 객체 자신의 내부 상태에 따라 행위를 변경&lt;span&gt;, &lt;/span&gt;객체는 마치 클래스를 변경하는 것처럼 동작한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Strategy &lt;/span&gt;패턴은 다양한 알고리즘이 존재하면 이들 각각을 하나의 클래스로 캡슐화하여 알고리즘을 대체하는 식으로 동작한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;&amp;eth;&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;클래스 다이어그램은 유사하나 의도가 다르다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;재귀적 포함&lt;/h1&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Composite &lt;/span&gt;패턴&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다형성을 이용하여 실행할 수 있도록 한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Leaf node&lt;/span&gt;가 다른&lt;span&gt; composite node&lt;/span&gt;들과 같은&lt;span&gt; layer&lt;/span&gt;에 존재하는&lt;span&gt; tree &lt;/span&gt;구조에서 유용하게 사용할 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개별 객체와 복합 객체를 구별하지 않고 동일한 방법으로 다룰 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Ex) &lt;/span&gt;메뉴 속 메뉴를 누르거나 메뉴 속 항목을 눌렀을 때&lt;span&gt;, &lt;/span&gt;같은&lt;span&gt; Base&lt;/span&gt;를 가지고 있다면&lt;span&gt;, &lt;/span&gt;즉 공통된 실행 함수&lt;span&gt;(&lt;/span&gt;하위 메뉴를 보여 주거나 항목 실행하는 게 동일한 함수라면&lt;span&gt;)&lt;/span&gt;가 있다면 타입에 관계없이 호출하면 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Cf) &lt;/span&gt;자식 클래스들 중 한 곳에서만 사용하는 함수이더라도 기반 클래스에 가상 함수로 선언하고&lt;span&gt; dummy &lt;/span&gt;구현을 해주면 동일하게 사용이 가능하다&lt;span&gt;. &lt;/span&gt;만약 모두가 사용한다면 순수 가상함수로 선언하면 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 든&lt;span&gt; Menu Event&lt;/span&gt;를 살펴보면 다음과 같다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;하는 일&lt;span&gt;(&lt;/span&gt;변하는 부분&lt;span&gt;)&lt;/span&gt;을 가상 함수로 분리한다&lt;span&gt;.&lt;br /&gt;-&amp;gt; &lt;/span&gt;메뉴의 개수만큼 파생 클래스를 만들어야 한다&lt;span&gt;. (&lt;/span&gt;너무 많아질 우려&lt;span&gt;)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;하는 일&lt;span&gt;(&lt;/span&gt;변하는 부분&lt;span&gt;)&lt;/span&gt;을 다른 클래스로 분리한다&lt;span&gt;. (Strategy &lt;/span&gt;패턴&lt;span&gt;, Listener&lt;/span&gt;라는 이름을 사용하는 기술&lt;span&gt;)&lt;br /&gt;-&amp;gt; &lt;/span&gt;어떤 메뉴인지 정보를 전달받는&lt;span&gt;(&lt;/span&gt;주로 인자&lt;span&gt;) &lt;/span&gt;절차가 필요하다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;메뉴에 객체가 아닌 함수를 연결한다&lt;span&gt;. &lt;/span&gt;즉&lt;span&gt;, &lt;/span&gt;같은 인터페이스를 사용하는 것이 아니라 함수 포인터를 전달 받아 사용한다&lt;span&gt;.&lt;br /&gt;-&amp;gt; &lt;/span&gt;단&lt;span&gt;, &lt;/span&gt;함수 포인터는 일반 함수와 멤버 함수의 포인터를 동시에 담을 수 없다&lt;span&gt;.&lt;br /&gt;-&amp;gt; &lt;/span&gt;각 함수 포인터를&lt;span&gt; wrapping&lt;/span&gt;하는 클래스를 공통의 기반 클래스를 가지도록 선언하여 사용한다&lt;span&gt;. &lt;/span&gt;이 때 함수 템플릿&lt;span&gt;(&lt;/span&gt;클래스 템플릿은&lt;span&gt; C++17~)&lt;/span&gt;은 타입을 명시적으로 지정하지 않아도 묵시적 추론이 되므로 생략 가능하다&lt;span&gt;. ~C++14&lt;/span&gt;에서는 클래스 템플릿을 생성하는 함수 템플릿을 도움 함수로 만들면 실제 사용 시 일반 함수와 멤버 함수가 통합된 형태로 사용이 가능하다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span&gt;Decorator&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실행 시간에 객체에 기능을 추가할 때 사용하는 패턴이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;(&lt;/span&gt;반대는 상속을 통한 객체 기능 추가이다&lt;span&gt;. &lt;/span&gt;상속을 통해 추가하는 건 인스턴스가 새로 생성되는 것으로 객체에 기능을 추가한 게 아니라 클래스에 기능을 추가하여 인스턴스를 변경한 개념이다&lt;span&gt;.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Composition&lt;/span&gt;을 통한 기능을 추가하면&lt;span&gt;(&lt;/span&gt;새 클래스가 기존 클래스를 멤버 변수로 가짐&lt;span&gt;) &lt;/span&gt;기존 객체에 기능이 추가된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;비교하자면 상속에 의한 추가는 클래스에 추가가 되고 코드 작성 시 추가의 개념이고&lt;span&gt;, &lt;/span&gt;구성을 통한 추가는 인스턴스에 추가가 되고 런타임에 추가의 개념이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능을 연속해서 추가하기 위해서는 기능이 추가되는 주체 객체와 기능 추가 객체들은 동일한 기반 클래스를 가져야 한다&lt;span&gt;. (ex. Base, Par1, Par2, Par3 &lt;/span&gt;등등이 공통의 기반 클래스를 가짐&lt;span&gt;).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;여기서 기능 추가 클래스들은 다시 공통의 기반 클래스&lt;span&gt;(IDecotator)&lt;/span&gt;로 묶을 수 있다&lt;/span&gt;&lt;/p&gt;</description>
      <category>Development/C++</category>
      <category>C++</category>
      <category>gof 패턴</category>
      <category>디자인 패턴</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/166</guid>
      <comments>https://icerabbit.tistory.com/166#entry166comment</comments>
      <pubDate>Tue, 21 Jan 2025 21:22:42 +0900</pubDate>
    </item>
    <item>
      <title>정규표현식 간단 정리</title>
      <link>https://icerabbit.tistory.com/165</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;개발을 할 때 종종 정규표현식을 사용할 일이 있습니다. 특정 패턴의 버전을 입력해야 하는 유효성 검사를 하거나, string으로 넘어온 인자들을 파싱할 때 등 여러 경우에 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근에는 언어에서 지원해주는 라이브러리들도 많고, 자주 쓰이는 패턴의 경우에는 검색하면 금방 나오기도 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 코딩과 마찬가지로 긁어서 가져다 쓰는 것만이 아니라 이해하고 활용하고, 수정하고 나아가서는 직접 만들 줄도 알아야 한다고 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 근래에 정규표현식 관련해서 책을 읽으면서 나름대로 정리한 내용입니다.(근래라고는 썼지만 몇 달 되긴 했네요.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://regexr.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://regexr.com/&lt;/a&gt; 와 같은 곳에서 직접 만들고 테스트해볼 수도 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;(혼자 정리용으로 필기한 글이라 최대한 가독성 좋게 수정하기는 했습니다만 잘 읽히지 않는 부분이 있을 수도 있습니다.)&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정규표현식&lt;span&gt;(Regular Expression, regex) : &lt;/span&gt;일치하는 텍스트를 찾거나&lt;span&gt;(&lt;/span&gt;검색&lt;span&gt;), &lt;/span&gt;찾은 텍스트를 치환하는&lt;span&gt;(&lt;/span&gt;치환&lt;span&gt;) &lt;/span&gt;도구&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;가장 쉽게는 문자를 그대로 찾을 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;This my car. &lt;/span&gt;에서 &lt;span&gt;my &lt;/span&gt;를 구문으로 찾으면 &lt;span&gt;my&lt;/span&gt;가 검색된다&lt;span&gt;. &lt;/span&gt;여러 일치된 결과물을 받을 수도 있다&lt;span&gt;. &lt;/span&gt;대소문자 구분은 하는 것이 디폴트이지만 옵션으로 구분하지 않을 수도 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;모든 문자에 대응하는 마침표&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;와일드카드로 마침표&lt;span&gt;(.)&lt;/span&gt;가 있다&lt;span&gt;. &lt;/span&gt;예를 들어 &lt;span&gt;c.t &lt;/span&gt;로 검색하면 &lt;span&gt;cat, cot &lt;/span&gt;등이 모두 검색된다&lt;span&gt;. &lt;/span&gt;마침표 한 개는 한 개의 아무 문자를 의미한다&lt;span&gt;. Sales.. &lt;/span&gt;로 검색하면 &lt;span&gt;Sales.hi, sales.hello &lt;/span&gt;등이 모두 검색된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 진짜 마침표를 찾고 싶다면 &lt;span&gt;escape&lt;/span&gt;문자로 &lt;span&gt;\. &lt;/span&gt;를 써주면 된다&lt;span&gt;. &lt;/span&gt;이것을 정규표현식에서는(다른 곳에서도 많이 쓰는 표현이지만) 메타 문자라고 한다&lt;span&gt;. &lt;/span&gt;역슬래시 자체는 &lt;span&gt;\\ &lt;/span&gt;이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;여러 문자의 집합&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 문자가 아니라 일부 문자만을 넣고 싶다면&lt;span&gt;, &lt;/span&gt;대괄호&lt;span&gt;([])&lt;/span&gt;로 일치하는 문자들을 넣을 수 있다&lt;span&gt;. &lt;/span&gt;특정 구역에서 대소문자를 구분하지 않을 때 많이 사용한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어 &lt;span&gt;[Rr]rg[Ee]X&lt;/span&gt;와 같은 식이다&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대괄호에 넣은 문자가 많을 경우에는 다 적기가 번거로우므로&lt;span&gt;, &lt;/span&gt;하이픈&lt;span&gt;(-)&lt;/span&gt;으로 범위를 지정할 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들어 &lt;span&gt;[ns]a[0-9]\.xls&lt;/span&gt;와 같은 식이다&lt;span&gt;. A-Z, a-z, A-F, A-z &lt;/span&gt;등으로 활용 가능하다&lt;span&gt;. &lt;/span&gt;여기서 하이픈은 대괄호 내에서만 유효한 메타 문자이므로&lt;span&gt;, &lt;/span&gt;대괄호 안이 아닌 이상 &lt;span&gt;\&lt;/span&gt;를 붙여줄 필요가 없다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;[A-Za-z0-9]&lt;/span&gt;는 모든 영문자&lt;span&gt;, &lt;/span&gt;숫자를 의미한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반면에 몇 개만 빼고 모두 찾아야할 경우에는 제외하는 것이 빠르다&lt;span&gt;. &lt;/span&gt;그럴 때에는 캐럿 문자&lt;span&gt;(^) &lt;/span&gt;를 사용한다&lt;span&gt;. &lt;/span&gt;다음과 같이 사용하면 숫자를 제외할 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;[ns]a[^0-9]\.xls&lt;/span&gt;이다&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;메타 문자&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상술했듯이 역슬래시&lt;span&gt;(\)&lt;/span&gt;를 활용한 &lt;span&gt;escape &lt;/span&gt;문자를 이용하여&lt;span&gt;, &lt;/span&gt;대괄호나 마침표 등을 검색할 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공백 문자는 &lt;span&gt;[\b] &amp;ndash; &lt;/span&gt;백스페이스&lt;span&gt;, \f &amp;ndash; &lt;/span&gt;페이지 넘김&lt;span&gt;, \n &amp;ndash; &lt;/span&gt;개행&lt;span&gt;, \t &amp;ndash; &lt;/span&gt;탭 등으로 검색할 수 있다&lt;span&gt;. &lt;/span&gt;덧붙여 마침표&lt;span&gt;(.)&lt;/span&gt;는 거의 모든 문자를 탐색하지만 대부분의 엔진에서 공백 문자는 제외된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추가적으로 윈도우에서는 &lt;span&gt;\r\n&lt;/span&gt;이 줄의 끝을 나타내고&lt;span&gt;, &lt;/span&gt;유닉스&lt;span&gt;/&lt;/span&gt;리눅스 계열에서는 &lt;span&gt;\n&lt;/span&gt;이 줄의 끝을 나타낸다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자 집합&lt;span&gt;, &lt;/span&gt;숫자 집합 등은 굉장히 자주 쓰이는 조합이기 때문에&lt;span&gt;, &lt;/span&gt;편의를 이유로 메타 문자로 해당 클래스들을 만들어 놓는다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;\d &amp;ndash; &lt;/span&gt;숫자 하나&lt;span&gt;, \D &amp;ndash; &lt;/span&gt;숫자를 제외한 문자 하나&lt;span&gt;, \w &amp;ndash; &lt;/span&gt;대소문 영문자&lt;span&gt;, &lt;/span&gt;숫자&lt;span&gt;, &lt;/span&gt;밑줄&lt;span&gt;, \W &amp;ndash; &lt;/span&gt;대소문 영문자 및 숫자 및 밑줄을 제외한 문자&lt;span&gt;, \s &amp;ndash; &lt;/span&gt;모든 공백 문자&lt;span&gt;, \S &lt;/span&gt;공백 문자가 아닌 문자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진수도 메타 문자로 쓸 수 있다&lt;span&gt;. 16&lt;/span&gt;진수는 &lt;span&gt;\x&lt;/span&gt;로 표시&lt;span&gt;, 8&lt;/span&gt;진수는 &lt;span&gt;\0&lt;/span&gt;으로 표기한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;POSIX &lt;/span&gt;문자 클래스로도 줄여 쓰기를 제공하는데&lt;span&gt;, [:alpha:]&lt;/span&gt;와 같이 대괄호와 콜론 사이에 단어가 들어간다&lt;span&gt;. &lt;/span&gt;단&lt;span&gt;, &lt;/span&gt;이는 자바스크립트에서는 지원하지 않는다&lt;span&gt;. POSIX&lt;/span&gt;는 자체로 대괄호를 문법에 포함하므로&lt;span&gt;, &lt;/span&gt;집합을 나타내는 대괄호와 함께 &lt;span&gt;[[:alpha:]]&lt;/span&gt;와 같이 사용되는 것이 일반적이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;반복 찾기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이전까지는 한 글자에 대한 찾기였으나 둘 이상의 글자를 찾는 것이 필요하다&lt;span&gt;. &lt;/span&gt;그럴 때 더하기&lt;span&gt;(+)&lt;/span&gt;를 뒤에 붙이면 하나 이상의 문자와 일치하는지를 찾는다&lt;span&gt;(ex. a+&lt;/span&gt;이면 연속되는 &lt;span&gt;a&lt;/span&gt;를 모두 찾는다&lt;span&gt;).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더하기는 최소한 하나의 일치하는 문자가 존재해야 하지만&lt;span&gt;, &lt;/span&gt;별표&lt;span&gt;(*)&lt;/span&gt;는 일치하는 문자가 존재하거나 아예 없거나이다&lt;span&gt;(&lt;/span&gt;불일치하는 경우만 걸러진다&lt;span&gt;).&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더해서 물음표&lt;span&gt;(?)&lt;/span&gt;는 더하기와 별표의 중간인데&lt;span&gt;, &lt;/span&gt;딱 한 문자가 일치하거나 문자가 존재하지 않거나이다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중괄호&lt;span&gt;({})&lt;/span&gt;를 사용해서 바로 앞 문자의 구간을 지정해 줄 수도 있다&lt;span&gt;. &lt;/span&gt;하나만 적으면 정확한 개수&lt;span&gt;, &lt;/span&gt;두 개를 적으면 개수의 범위이다&lt;span&gt;. &lt;/span&gt;쉼표를 적으면 최소한의 의미가 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Ex) \d{1,2}\d{3}\d{3,}&lt;br /&gt;1&lt;/span&gt;개 이상 &lt;span&gt;2&lt;/span&gt;개 이하의 숫자&lt;span&gt;, 3&lt;/span&gt;개의 숫자&lt;span&gt;, &lt;/span&gt;최소한 &lt;span&gt;3&lt;/span&gt;개의 숫자&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;과도하게 일치하는 것을 방지하기 위해 &lt;span&gt;lazy &lt;/span&gt;수량자를 이용한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;*&lt;/span&gt;는 &lt;span&gt;*?, +&lt;/span&gt;는&lt;span&gt; +?, {n,}&lt;/span&gt;는 &lt;span&gt;{n,}?&lt;/span&gt;이다&lt;span&gt;. &lt;/span&gt;일치하는 최소한의 문자만을 찾는다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;위치 찾기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위치 찾기는 문자열 내에서 반드시 일치해야 하는 위치를 지정할 때 사용한다&lt;span&gt;. Cat&lt;/span&gt;을 검색했는데 &lt;span&gt;cat&lt;/span&gt;과 &lt;span&gt;scatter&lt;/span&gt;가 모두 검색되는 등의 문제를 방지하기 위함&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 문제는 앞뒤로 단어의 끝을 나타내는 &lt;span&gt;\b&lt;/span&gt;를 삽입하여 해결할 수 있다&lt;span&gt;(\bcat\b). \b&lt;/span&gt;는 단어가 아니라 위치를 가리키기 때문에&lt;span&gt;, &lt;/span&gt;찾은 문자열의 길이는 &lt;span&gt;3&lt;/span&gt;이 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어 경계를 반대로 제외시키고 싶을 때에는 &lt;span&gt;\B&lt;/span&gt;를 사용한다&lt;span&gt;. &lt;/span&gt;메타 문자에서 대소문자는 주로 반대의 역할을 가진다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캐럿&lt;span&gt;(^) &lt;/span&gt;문자는 문자열의 시작을 의미한다&lt;span&gt;. &lt;/span&gt;즉&lt;span&gt;, &lt;/span&gt;반드시 &lt;span&gt;1&lt;/span&gt;째 줄의 시작이어야 하는 경우에 사용할 수 있다&lt;span&gt;. [^&lt;/span&gt;로 쓰일 경우에는 부정을 의미하지만&lt;span&gt;, &lt;/span&gt;대괄호 바깥에서는 문자열의 시작으로 쓰인다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;$ &lt;/span&gt;문자는 반대로 문자열의 끝이다&lt;span&gt;. &lt;/span&gt;즉&lt;span&gt;, &lt;/span&gt;마지막 줄의 끝이어야 하는 경우에 사용한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;?m&lt;/span&gt;을 정규표현식 맨 앞에 붙여 다중 행을 지원한다면&lt;span&gt;, ^&lt;/span&gt;와 &lt;span&gt;$&lt;/span&gt;는 줄바꿈 문자를 문자열의 시작&lt;span&gt;/&lt;/span&gt;끝으로 같이 인식하게 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;하위 표현식 사용하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반복 메타 문자는 자신의 바로 앞 한 글자에 대해서만 작동한다&lt;span&gt;. &lt;/span&gt;예를 들어 &lt;span&gt;&amp;amp;nbsp;{2,}&lt;/span&gt;의 경우에는 &lt;span&gt;&amp;amp;nbsp;&lt;/span&gt;가 반복되는 것을 찾고 싶었으나 &lt;span&gt;;&lt;/span&gt;만의 반복을 찾게 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 하위 표현식을 사용하면 된다&lt;span&gt;. &lt;/span&gt;소괄호로 묶으면 된다&lt;span&gt;. (&amp;amp;nbsp;){2,}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;괄호 안에는 정규 표현식이 들어갈 수도 있다&lt;span&gt;. (\d{1,3}\.){3}&lt;/span&gt;과 같은 식&lt;span&gt;. &lt;/span&gt;반복하려는 패턴의 영역을 정의하거나 &lt;span&gt;OR &lt;/span&gt;조건을 적절하게 정의할 때 주로 사용된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;물론 응용하여 중첩&lt;span&gt;(nested)&lt;/span&gt;도 가능하다&lt;span&gt;. &lt;/span&gt;괄호 안의 괄호&lt;/p&gt;
&lt;h1&gt;역참조 사용하기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역참조는 패턴 중 하나로&lt;span&gt;, &lt;/span&gt;앞서 일치한 부분을 다시 가리키는 패턴이다&lt;span&gt;. &lt;/span&gt;하위표현식의 맨 끝에 &lt;span&gt;\1&lt;/span&gt;을 붙이면 앞에 일치했던 패턴과 일치하는지를 찾게 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Ex) [ ]+(\w+)[ ]+\1 : &lt;/span&gt;앞뒤로 공백이 하나 이상이며&lt;span&gt;, &lt;/span&gt;문자가 하나 이상 등장하는 하위 표현식이 등장한다&lt;span&gt;. &lt;/span&gt;마지막의 &lt;span&gt;\1&lt;/span&gt;는 앞서 일치한 하위 표현식이 또 있는지를 확인한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;\1&lt;/span&gt;은 처음 사용한 하위 표현식과 일치하는지를 확인한다&lt;span&gt;. \2&lt;/span&gt;는 두 번째&lt;span&gt;, \3&lt;/span&gt;는 세 번째&lt;span&gt;&amp;hellip;&lt;/span&gt;와 같은 사용이 가능하다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역참조 문법은 정규 표현식 구현에 따라서 상이한 경우가 많으므로&lt;span&gt;, &lt;/span&gt;해당 스택에서의 용법을 확인하고 사용할 것&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;l&lt;span&gt;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;치환 작업을 할 때에는 정규 표현식이 두 개 필요하다&lt;span&gt;. &lt;/span&gt;검색할 때 사용하는 표현식&lt;span&gt;, &lt;/span&gt;치환할 때 사용하는 표현식&lt;span&gt;. &lt;/span&gt;아래 예제를 보자&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이메일을 검색하여 &lt;span&gt;href &lt;/span&gt;형태로 바꿀 때 역참조로 간단하게 할 수 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;검색 패턴 &lt;span&gt;: (\w+[\w\.]&lt;a href=&quot;mailto:*@[\w\.%5d+\.\w&quot;&gt;*@[\w\.]+\.\w&lt;/a&gt;+)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;치환 패턴 &lt;span&gt;: &amp;lt;A HREF=&lt;a href=&quot;mailto:$1&quot;&gt;mailto:$1&lt;/a&gt;&amp;gt;$1&amp;lt;/A&amp;gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 치환 패턴에서 &lt;span&gt;$1&lt;/span&gt;이 역참조를 담당하고 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;전후방탐색&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문자열 자체가 아닌&lt;span&gt;, &lt;/span&gt;문자열의 위치를 찾고 싶은 경우에 탐색&lt;span&gt;(look around)&lt;/span&gt;를 사용한다&lt;span&gt;. &lt;/span&gt;예를 들어&lt;span&gt;, &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt; &lt;/span&gt;태그 사이에 있는 문자만을 결과로 조회하고 싶은 경우&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전방 탐색은 일치 영역을 발견해도 그 값을 반환하지 않는 패턴이다&lt;span&gt;. &lt;/span&gt;실제로는 하위 표현식이다&lt;span&gt;. ?=&lt;/span&gt;로 시작하고 &lt;span&gt;= &lt;/span&gt;다음에 일치할 텍스트가 온다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Ex) .+(?=:) &lt;/span&gt;와 같이 작성을 하면&lt;span&gt;, &lt;/span&gt;콜론이 등장하기 전까지의 텍스트가 반환된다&lt;span&gt;. &lt;/span&gt;만일 전방 탐색을 빼면 콜론까지 포함한 값이 반환된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;후방 탐색은 뒤쪽을 탐색하는데&lt;span&gt;, ?&amp;lt;=&lt;/span&gt;이다&lt;span&gt;. &lt;/span&gt;전방 탐색과 사용법이 같고&lt;span&gt;, &lt;/span&gt;일치하는 뒷부분을 반환한다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Ex) (?&amp;lt;=/$)[0-9.]+&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;맨 첫 태그 내 텍스트를 가져오는 경우와 같이&lt;span&gt;, &lt;/span&gt;전후방탐색을 함께 사용할 수도 있다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에 적은 전후방탐색의 반대 표현인 부정형 전후방탐색도 있는데 &lt;span&gt;= &lt;/span&gt;대신에 &lt;span&gt;!&lt;/span&gt;를 사용하면 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;?! &lt;/span&gt;와 &lt;span&gt;?&amp;lt;!&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;조건 달기&lt;/h1&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조건을 사용할 때에는 &lt;span&gt;?&lt;/span&gt;를 사용하는데&lt;span&gt;, &lt;/span&gt;이전에 썼던 것들 중 역참조&lt;span&gt;, &lt;/span&gt;전후방탐색을 사용하여 조건 처리가 가능하다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;역참조 조건은 &lt;span&gt;(?(&lt;/span&gt;역참조 표현&lt;span&gt;)true)&lt;/span&gt;로 쓸 수 있다&lt;span&gt;. (?(&lt;/span&gt;역참조 표현&lt;span&gt;)true|false)&lt;/span&gt;로 하면 &lt;span&gt;else&lt;/span&gt;문과 같이 동작한다&lt;span&gt;. &lt;/span&gt;즉&lt;span&gt;, ?&lt;/span&gt;로 시작한 역참조 표현이 존재하면 &lt;span&gt;true &lt;/span&gt;위치에 있는 표현식이&lt;span&gt;, &lt;/span&gt;없으면 &lt;span&gt;false &lt;/span&gt;위치의 표현식이 동작한다&lt;span&gt;. &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전후방탐색은 역참조와 동일하게 사용하면 된다&lt;span&gt;.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Development</category>
      <category>Regex</category>
      <category>정규표현식</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/165</guid>
      <comments>https://icerabbit.tistory.com/165#entry165comment</comments>
      <pubDate>Tue, 14 Jan 2025 21:30:35 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] 344. Reverse String</title>
      <link>https://icerabbit.tistory.com/164</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/reverse-string/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/reverse-string/&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;char 배열로 들어있는 string을 뒤바꾸는 간단명료한 문제이다. 참고로 일부 언어들에서 .resverse를 지원하기도 하지만 이를 방지하기 위해 모든 언어에서 char 배열로 input을 제공한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인은 stack에 넣고 앞부터 차례대로 넣어주도록 간단하게 구현하였다.&lt;/p&gt;
&lt;pre id=&quot;code_1729684228127&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
public:
    void reverseString(vector&amp;lt;char&amp;gt;&amp;amp; s) {
        stack&amp;lt;char&amp;gt; stack;
        for(char ch : s) {
            stack.push(ch);
        }
        int i=0;
        while(!stack.empty()) {
            s[i++] = stack.top();
            stack.pop();
        }
    }
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>PS/LeetCode</category>
      <category>C++</category>
      <category>leetcode</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/164</guid>
      <comments>https://icerabbit.tistory.com/164#entry164comment</comments>
      <pubDate>Wed, 23 Oct 2024 20:51:16 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] 144. Binary Tree Preorder Traversal</title>
      <link>https://icerabbit.tistory.com/163</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/binary-tree-preorder-traversal/description/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/binary-tree-preorder-traversal&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Tree가 주어질 경우 이 값을 root부터 순차적으로 값을 배열에 저장하는 심플한 문제이다.&lt;/p&gt;
&lt;pre id=&quot;code_1729683897540&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector&amp;lt;int&amp;gt; preorderTraversal(TreeNode* root) {
        vector&amp;lt;int&amp;gt; answer;
        TreeNode* current = root;
        vector&amp;lt;TreeNode*&amp;gt; parents;
        int count = 0;
        if(root == nullptr) {
            return answer;
        }
        do {
            if(current-&amp;gt;val &amp;gt; -101) {
                answer.push_back(current-&amp;gt;val);
                current-&amp;gt;val = -101;
            }

            if(current-&amp;gt;left != nullptr) {
                parents.push_back(current);
                current = current-&amp;gt;left;
                parents.back()-&amp;gt;left = nullptr;
            } else if(current-&amp;gt;right != nullptr) {
                parents.push_back(current);
                current = current-&amp;gt;right;
                parents.back()-&amp;gt;right = nullptr;
            } else if (!parents.empty()) {
                current = parents.back();
                parents.pop_back();
            }
            if(parents.empty()) {
                ++count;
            }
        } while(count &amp;lt; 2);

        return answer;
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-100~100의 값을 가지는 조건이어서 지나갈 경우 지나간 표시로 그 외의 값을 넣어 주고 부모들을 모아 두는 벡터에 저장한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 left부터 순회하면서 값을 저장하도록 하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/binary-tree-postorder-traversal&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/binary-tree-postorder-traversal&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;155번 문제는 후위로 담는 문제로, 거꾸로 자식 노드부터 넣도록 하면 되는데 위 코드와 유사한 점이 많다.&lt;/p&gt;
&lt;pre id=&quot;code_1729684060679&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    vector&amp;lt;int&amp;gt; postorderTraversal(TreeNode* root) {
        vector&amp;lt;int&amp;gt; answer;
        TreeNode* current = root;
        vector&amp;lt;TreeNode*&amp;gt; parents;
        int count = 0;
        if(root == nullptr) {
            return answer;
        }
        do {
            if(current-&amp;gt;left != nullptr) {
                parents.push_back(current);
                current = current-&amp;gt;left;
                parents.back()-&amp;gt;left = nullptr;
            } else if(current-&amp;gt;right != nullptr) {
                parents.push_back(current);
                current = current-&amp;gt;right;
                parents.back()-&amp;gt;right = nullptr;
            } else {
                if(current-&amp;gt;val &amp;gt; -101) {
                    answer.push_back(current-&amp;gt;val);
                    current-&amp;gt;val = -101;
                }
                if (!parents.empty()) {
                    current = parents.back();
                    parents.pop_back();
                }
            }
            if(parents.empty()) {
                ++count;
            }
        } while(count &amp;lt; 3);

        return answer;
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>PS/LeetCode</category>
      <category>C++</category>
      <category>leetcode</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/163</guid>
      <comments>https://icerabbit.tistory.com/163#entry163comment</comments>
      <pubDate>Wed, 23 Oct 2024 20:48:47 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] 112. Path Sum</title>
      <link>https://icerabbit.tistory.com/162</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/path-sum/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/path-sum/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;421&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BWiTW/btsFDCkqUhO/K9ynaHn7UoP3NcyiKEHwd1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BWiTW/btsFDCkqUhO/K9ynaHn7UoP3NcyiKEHwd1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BWiTW/btsFDCkqUhO/K9ynaHn7UoP3NcyiKEHwd1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBWiTW%2FbtsFDCkqUhO%2FK9ynaHn7UoP3NcyiKEHwd1%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;592&quot; height=&quot;421&quot; data-origin-width=&quot;592&quot; data-origin-height=&quot;421&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;tree에서 root~leaf 까지의 합이 주어진 값과 일치하는 경우가 있는지 확인하는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학부생 시절 코딩테스트를 준비할 때에는 tree 문제를 아주 많이 풀었으나, 요즘에는 잘 풀지 않아 DFS라는 개념만 기억하고 있었다. 따로 예전의 스킬을 찾아 보지는 않고, 논리에 맞게 생각하면서 분기를 태웠다. 아래가 제출한 코드인데, 분기 코드가 좀 지저분하다. 주어진 TreeNode가 부모는 갖고 있지 않아 stack에 push/pop하면서 비교하고, 한 쪽만 비거나 양 쪽 모두 비었을 경우 모두를 분기하느라 분기 조건이 길어졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제 또한 요즘 C++을 사용하고 있어 문제도 C++로 풀어 보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1709816152228&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    bool hasPathSum(TreeNode* root, int targetSum) {
        bool result = false;
        if(root == nullptr) {
            return result;
        }

        std::stack&amp;lt;TreeNode*&amp;gt; st;
        st.push(root);
        auto iterNode = st.top();
        TreeNode* popNode = nullptr;
        int sum = tempNode-&amp;gt;val;
        int count = 0;
        while(!st.empty()) {
            iterNode = st.top();
            if (iterNode == root) {
                if ((root-&amp;gt;left == nullptr &amp;amp;&amp;amp; root-&amp;gt;right == nullptr) &amp;amp;&amp;amp; ++count == 1) {
                    result = (root-&amp;gt;val == targetSum);
                    break;
                } else if ((root-&amp;gt;left == nullptr || root-&amp;gt;right == nullptr) &amp;amp;&amp;amp; ++count == 2) {
                    break;
                } else if (++count == 3) {
                    break;
                }
            }
            if(iterNode-&amp;gt;left != nullptr &amp;amp;&amp;amp; popNode != iterNode-&amp;gt;left &amp;amp;&amp;amp; (popNode != iterNode-&amp;gt;right || popNode == nullptr || iterNode-&amp;gt;right == nullptr)) {
                sum += iterNode-&amp;gt;left-&amp;gt;val;
                st.push(iterNode-&amp;gt;left);
                continue;
            } else if(iterNode-&amp;gt;right != nullptr &amp;amp;&amp;amp; popNode != iterNode-&amp;gt;right) {
                sum += iterNode-&amp;gt;right-&amp;gt;val;
                st.push(iterNode-&amp;gt;right);
                continue;
            } else {
                if (sum == targetSum &amp;amp;&amp;amp; iterNode-&amp;gt;left == nullptr &amp;amp;&amp;amp; iterNode-&amp;gt;right == nullptr) {
                    result = true;
                    break;
                }
                popNode = st.top();
                sum -= popNode-&amp;gt;val;
                st.pop();
            }
        }

        return result;
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위에서 말했듯이 우선 while문 내에서 stack에 넣고 빼기를 하도록 하고 그 후에 분기들을 붙이느라 여러 케이스들이 많아 조건문이 길고 보기 복잡해졌다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제풀이를 가끔씩 하던 터라 감을 잡기 위해 이번에는 따로 공부하지 않고 논리로 풀었으나, 좀 더 간결하게 짤 수 있도록 해야겠다.&lt;/p&gt;</description>
      <category>PS/LeetCode</category>
      <category>leetcode</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/162</guid>
      <comments>https://icerabbit.tistory.com/162#entry162comment</comments>
      <pubDate>Thu, 7 Mar 2024 21:57:36 +0900</pubDate>
    </item>
    <item>
      <title>[LeetCode] 58. Length of Last Word</title>
      <link>https://icerabbit.tistory.com/161</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/length-of-last-word&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/length-of-last-word&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제 구성은 매우 쉽게 이해할 수 있다. 띄어쓰기를 구분으로 주어지는 문장에서, 마지막 단어의 길이를 반환하면 된다. 금방 풀 수 있고, 연속해서 공백이 나오거나 앞뒤에 공백이 주어지는 점만 주의하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;본인은 공백을 기준으로 자르고, 마지막이 공백인 경우를 제외할 수 있도록 처리하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;근래에 계속 Python을 이용해서 풀다가, 요즘에는 현업에서 C++을 사용하고 있기에 C++로 풀어보았다.&lt;/p&gt;
&lt;pre id=&quot;code_1709814796483&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution {
public:
    int lengthOfLastWord(string s) {
        std::istringstream iss(s);

        std::vector&amp;lt;std::string&amp;gt; tokens;

        std::string token;
        std::string old_token;
        while (std::getline(iss, token, ' ')) {
            if (token.empty()) {
                continue;
            }
            old_token = token;
        }


        return old_token.size();
    }
};&lt;/code&gt;&lt;/pre&gt;</description>
      <category>PS/LeetCode</category>
      <category>leetcode</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/161</guid>
      <comments>https://icerabbit.tistory.com/161#entry161comment</comments>
      <pubDate>Thu, 7 Mar 2024 21:34:38 +0900</pubDate>
    </item>
    <item>
      <title>[flutter] Unable to find bundled Java version 오류가 발생할 경우</title>
      <link>https://icerabbit.tistory.com/160</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Windows 환경에서 flutter 설치 후에 flutter doctor를 실행했을 때 Unable to find bundled Java version 오류가 발생하는 경우가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Android Studio 버전이 올라가면서 오류가 발생하는 것으로 추정되는데 아래와 같이 해결 가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 안드로이드가 설치된 경로(기본은 C:\Program Files\Android\Android Studio) 하위의 jbr 폴더 내용을 jre 폴더에 붙여넣는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 명령 프롬프트(cmd)를 관리자 권한으로 실행하고, 심볼릭 링크를 생성한다.&lt;br /&gt;ex) &lt;span style=&quot;background-color: #ffffff; color: #24292f; text-align: start;&quot;&gt;mklink /d &quot;C:\Program Files\Android\Android Studio\jre&quot; &quot;C:\Program Files\Android\Android Studio\jbr&quot;&lt;/span&gt;&lt;/p&gt;</description>
      <category>Development</category>
      <category>Flutter</category>
      <category>플러터</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/160</guid>
      <comments>https://icerabbit.tistory.com/160#entry160comment</comments>
      <pubDate>Wed, 27 Dec 2023 22:01:22 +0900</pubDate>
    </item>
    <item>
      <title>[LeedCode] 268. Missing Number</title>
      <link>https://icerabbit.tistory.com/159</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/missing-number/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://leetcode.com/problems/missing-number/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1703681624543&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;Missing Number - LeetCode&quot; data-og-description=&quot;Can you solve this real interview question? Missing Number - Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array. &amp;nbsp; Example 1: Input: nums = [3,0,1] Output: 2 Explanatio&quot; data-og-host=&quot;leetcode.com&quot; data-og-source-url=&quot;https://leetcode.com/problems/missing-number/&quot; data-og-url=&quot;https://leetcode.com/problems/missing-number/description&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/YW6j3/hyUTwink0n/n8DQxCYdSg4xrbm6FyXZ4K/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260&quot;&gt;&lt;a href=&quot;https://leetcode.com/problems/missing-number/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://leetcode.com/problems/missing-number/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/YW6j3/hyUTwink0n/n8DQxCYdSg4xrbm6FyXZ4K/img.png?width=500&amp;amp;height=260&amp;amp;face=0_0_500_260');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;Missing Number - LeetCode&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Can you solve this real interview question? Missing Number - Given an array nums containing n distinct numbers in the range [0, n], return the only number in the range that is missing from the array. &amp;nbsp; Example 1: Input: nums = [3,0,1] Output: 2 Explanatio&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;leetcode.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제는 매우 직관적으로 이해할 수 있다. 중복이 없는 n 길이의 0~n 배열이 주어지는데, 이 중 한 숫자가 비어 있는데 이를 찾으면 되는 문제이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 단순하게는 O(n)으로 순회하면서 없는 값을 반환하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1703681727435&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def missingNumber(self, nums):
        &quot;&quot;&quot;
        :type nums: List[int]
        :rtype: int
        &quot;&quot;&quot;
        for i in range(0, len(nums)+1):
            if i not in nums:
                return i
        return 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(1)로 풀려면, IQ테스트 같긴 하지만 0부터 n까지의 숫자가 주어진다는 점을 착안하여,1부터 n까지 더한 값과의 차를 구하면 O(1)로 풀 수 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1703681840895&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Solution(object):
    def missingNumber(self, nums):
        &quot;&quot;&quot;
        :type nums: List[int]
        :rtype: int
        &quot;&quot;&quot;
        n = len(nums)
        return ((n * (n+1)) // 2 ) - sum(nums)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>PS/LeetCode</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/159</guid>
      <comments>https://icerabbit.tistory.com/159#entry159comment</comments>
      <pubDate>Wed, 27 Dec 2023 21:57:45 +0900</pubDate>
    </item>
    <item>
      <title>[소공] 클래스 모델링</title>
      <link>https://icerabbit.tistory.com/158</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;OOP로 프로그래밍할 때에는 코드 작성 전에 클래스 모델링을 진행하는 편이 좋다. 학부생 때 다들 그려봤을 클래스 다이어그램을 이용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 다이어그램의 구성 요소는 아래와 같다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스 : 자료 타입 그 자체를 나타냄&lt;/li&gt;
&lt;li&gt;연관 관계 : 클래스 인스턴스 사이의 관계를 나타냄&lt;/li&gt;
&lt;li&gt;속성 : 클래스와 그 인스턴스 내에서 발견되는 단순 자료&lt;/li&gt;
&lt;li&gt;오퍼레이션 : 클래스와 그 인스턴스에 의해 수행될 함수&lt;/li&gt;
&lt;li&gt;일반화 : 클래스를 상속 구조로 그루핑&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첨언하자면 클래스와 인스턴스는 붕어빵 틀과 붕어빵의 관계인데, 여기서는 더 자세히 다루지는 않겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 다이어그램에서 클래스는 박스로 표현하며 그 안에 이름을 적는다. 그 아래에 속성과 타입을 적고, 그 아래에 오퍼레이션을 적는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시로 보면 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;484&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qSBub/btsytsCHT3p/bX0eM2ytdLVRqLkiSi5WAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qSBub/btsytsCHT3p/bX0eM2ytdLVRqLkiSi5WAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qSBub/btsytsCHT3p/bX0eM2ytdLVRqLkiSi5WAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqSBub%2FbtsytsCHT3p%2FbX0eM2ytdLVRqLkiSi5WAK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;528&quot; height=&quot;484&quot; data-origin-width=&quot;528&quot; data-origin-height=&quot;484&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 이미지에 더하여 접근 지정자도 나타낼 수 있는데, public은 +, protected는 #, private는 -로 표시한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스는 혼자 존재하는 것이 아니고 상속, 참조 등 연관 관계를 지니게 되는데, 이 또한 다이어그램으로 표시할 수 있다. 예시는 아래와 같다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;569&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/etohLS/btsyukKVvqO/e6buewd4tFcKDfk5uwj371/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/etohLS/btsyukKVvqO/e6buewd4tFcKDfk5uwj371/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/etohLS/btsyukKVvqO/e6buewd4tFcKDfk5uwj371/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FetohLS%2FbtsyukKVvqO%2Fe6buewd4tFcKDfk5uwj371%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;761&quot; height=&quot;569&quot; data-origin-width=&quot;761&quot; data-origin-height=&quot;569&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;연관 관계에는 아래와 같은 관계가 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;One-to-one : 일대일 관계&lt;/li&gt;
&lt;li&gt;Many-top-may : 다대다 관계&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반화 관계의 경우 두 가지 이상의 서브 클래스로 구체화시키는 것이다. 즉, 공통되는 부분을 상속으로 가진다. 필자는 코딩할 때 중복을 제거하는 것이 가장 근본적인 자세라고 생각하는 편이라, 상당히 적용하기에 중요한 스킬이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다만 이것에 매몰되어 인스턴스 등으로 해결할 수 있는 부분을 무리하게 상속 구조로 바꾸는 것은 주의하여야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 일련의 과정을 정리해보면 아래와 같이 진행할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스 후보 선정 -&amp;gt; 연관 관계/속성 추가, 일반화 관계 파악, 클래스의 의존성 파악 -&amp;gt; 오퍼레이션 파악 -&amp;gt; 설계 패턴 적용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때, 위 과정을 한 번만 하고 끝나는 것이 아니라 추후 필요할 경우에는 과정을 반복하여 모델링하여 패턴 적용이 필요하다.&lt;/p&gt;</description>
      <category>Development/Software Architecture</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/158</guid>
      <comments>https://icerabbit.tistory.com/158#entry158comment</comments>
      <pubDate>Sat, 14 Oct 2023 12:54:46 +0900</pubDate>
    </item>
    <item>
      <title>[K8S] Pod 내부에서 Sidecar Container 사용하기</title>
      <link>https://icerabbit.tistory.com/157</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;K8S가 배포된 환경에서 Pod의 네트워크 탐지/분석 등 디버깅이나 추가적인 작업이 필요한 경우가 있다.&lt;br /&gt;기본적으로 Pod Container 내부에서는 관련 기능/툴이 제공되지 않는데, 이럴 때 Pod 내부에 sidecar 컨테이너를 띄워서 원하는 작업을 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;deploy.yaml에 pod 정보를 다음과 같이 추가한다. 어려운 부분은 없고 단순히 추가만 하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1669730170487&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# ...
spec:
    containers:
    - name: main-container
      image: {my-url}
      # ...
      
      # 아래에 sidecar container 정보를 추가한다.
    - name: side-container
      image: {my-url2}
      resources:
      # ...
# ...&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후에 kubectl apply -f deploy.yaml과 같이 위 설정을 적용하면, Pod에 컨테이너가 하나 더 실행됨을 확인할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;확인 후, kubectl exec -it &amp;lt;pod_name&amp;gt; -n &amp;lt;container_name&amp;gt; -- bash 명령어를 통해 진입할 수 있는데, side-container로 진입하면 해당 container 내에 설치된 툴/기능들을 실행할 수 있다.&lt;br /&gt;(container_name을 지정해 주지 않으면 내부 진입이 되지 않으므로, main-container 진입을 원할 경우에도 명시해줘야 한다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Pod 내부 트래픽 등에 접근할 수 있기 때문에, 디버깅에 용이하다. 아직 본인은 다른 용도로는 사용해보지 않았고, 디버깅 용도로 주로 사용했다.&lt;/p&gt;</description>
      <category>Development/Infra</category>
      <category>k8s</category>
      <category>SIDECAR</category>
      <author>판교토끼</author>
      <guid isPermaLink="true">https://icerabbit.tistory.com/157</guid>
      <comments>https://icerabbit.tistory.com/157#entry157comment</comments>
      <pubDate>Tue, 29 Nov 2022 22:59:12 +0900</pubDate>
    </item>
  </channel>
</rss>