프로그래밍백엔드 개발자

Perl에서 s/// 형식의 정규 표현식 작업은 어떻게 구현되며, 탐욕적(re greedy) 및 게으른(lazy) 패턴의 차이점은 무엇인가요? 다중 행 문자열을 올바르게 처리하는 방법과 예상치 못한 결과를 피하는 방법은 무엇인가요?

Hintsage AI 어시스턴트로 면접 통과

답변.

Perl은 정규 표현식이 깊은 수준에서 통합된 언어 중 하나입니다. 주요 교체 연산자는 s///로, 이는 패턴에 따라 문자열의 조각을 검색하고 변경하는 데 사용됩니다. 이 구조에는 특히 탐욕적/게으른 패턴, 다중 행 처리 및 교체 옵션 작업 시 여러 미세한 사항이 숨어 있습니다.

질문의 역사

s/// 연산자는 Perl의 초기 버전부터 존재하며, Perl은 이후 다른 언어들이 채택한 정규 표현식 구문 기본을 설정했습니다. 패턴 구성 및 수정자(g, m, s, i, x 등)의 대부분의 미세한 사항들은 Perl에서 발전했습니다.

문제

실제로 많은 개발자들이 탐욕적 수량자를 잘못 사용하거나 수정자(특히 sm)를 혼동하여, 다중 행 텍스트나 대용량 데이터에서 교체 시 예상치 못한 결과를 초래합니다. 문자열에서 하나의 일치 항목을 기대할 때 다른 것이 반환되거나, 첫 번째/마지막 발생만 교체될 수 있습니다.

해결책

패턴을 올바르게 선택하고 설정하는 것이 중요하며, 수정자의 작동 방식을 이해해야 합니다. 탐욕적 패턴(예: .*)은 가능한 최대 범위를 캡처하고, 게으른 패턴(예: .*?)은 최소한 필요한 범위를 캡처합니다.

수정자 작업:

  • g — 모든 일치 항목에 대해 교체를 수행합니다.
  • s — 다중 행 문자열 처리를 포함하여, 여기서 점(.)은 줄 바꿈 문자를 캡처합니다.
  • m — ^ 및 $ 기호의 동작을 변경합니다.

예: 태그 <tag> ... </tag>를 한 번에 하나의 태그만 스페이스로 교체하기 (게으른):

my $text = 'a <tag>1</tag> <tag>2</tag> b'; $text =~ s/<tag>.*?<\/tag>//g; print $text; # a b

다중 행 문자열 처리:

my $data = "Line 1 Line 2 <tag> DATA </tag> End"; $data =~ s/<tag>.*?<\/tag>//gs; print $data;

주요 특징:

  • 탐욕적 패턴은 최대 범위를 캡처하며, 게으른 패턴은 최소 범위를 캡처합니다.
  • 수정자 s는 점(.)이 줄 바꿈을 캡처하게 합니다.
  • 수정자 g는 수행된 교체의 수에 영향을 미칩니다.

함정 질문.

여러 태그를 처리할 때, 탐욕적 . 뒤에 ?를 명시하지 않으면 어떻게 되나요?*

탐욕적 수량자는 가능한 최대 범위를 캡처하게 되며, 중간 태그를 포함하게 되어 예상치 못하게 첫 번째 <tag>와 마지막 </tag> 사이의 모든 것을 삭제합니다:

my $txt = 'A <tag>1</tag> <tag>2</tag> B'; $txt =~ s/<tag>.*<\/tag>//g; print $txt; # A B

여기서 첫 번째 <tag>와 마지막 </tag> 사이의 모든 부분이 교체되었습니다.

Perl의 정규 표현식에서 m 수정자와 s 수정자의 차이점은 무엇인가요?

s — 점(.)이 줄 바꿈 문자를 캡처합니다; m — 다중 행 텍스트 내에서 ^와 $의 작업을 변경합니다. 이들의 용도는 다르지만 종종 헷갈립니다.

my $s = "abc def"; # /^def/는 m 없이 작동하지 않습니다. print $s =~ /^def/m; # 1 (true)

s///를 단 한 번만 적용하여 패턴의 모든 발생을 처리하는 방법은 무엇인가요?

g 수정자가 없으면 첫 번째 발생만 교체됩니다. 글로벌 교체를 위해 g를 추가해야 합니다:

my $s = "foo bar foo"; $s =~ s/foo/baz/g; # 두 번 모두 foo를 교체합니다.

일반적인 오류 및 안티 패턴

  • 필요할 때 게으른 패턴 대신 탐욕적 패턴 사용으로 인해 불필요한 데이터 캡처
  • 교체가 첫 번째 일치 항목만 이루어지도록 하는 g 수정자를 누락
  • 다중 행 데이터 작업 시 s 및 m 수정자를 무시

실제 예

부정적 사례

개발자가 HTML 태그 교체를 이렇게 작성하는 경우:

$text =~ s/<tag>.*<\/tag>//g;

결과적으로 모든 태그와 그 사이의 내용이 삭제됩니다 — 각각 따로가 아니라.

장점:

  • 간결하고 이해하기 쉬운 코드
  • 단일 일치에 대해 빠르게 작동합니다.

단점:

  • 비슷한 여러 조각에 대해 잘못된 결과를 초래합니다.
  • 나머지 구조의 일관성을 깨뜨립니다.

긍정적 사례

게으른 패턴과 올바른 수정자를 사용하는 것이 좋습니다:

$text =~ s/<tag>.*?<\/tag>//gs;

장점:

  • 각 블록이 올바르게 교체됩니다.
  • 불필요한 캡처가 없습니다.

단점:

  • 게으른 패턴과 수정자의 구문을 알아야 합니다.