Main Content

동적 정규 표현식

소개

동적 표현식에서는 입력 텍스트의 내용에 따라 regexp가 일치시킬 패턴을 만들 수 있습니다. 이런 방법으로, 구문 분석되는 텍스트의 다양한 입력 패턴과 더욱 세밀하게 일치시킬 수 있습니다. regexprep 함수에 사용할 대체어에도 동적 표현식을 사용할 수 있습니다. 이렇게 하면 구문 분석된 입력값에 맞게 대체 텍스트를 조정할 수 있습니다.

다음 명령의 match_expr 또는 replace_expr 인수에 임의 개수의 동적 표현식을 포함시킬 수 있습니다.

regexp(text, match_expr)
regexpi(text, match_expr)
regexprep(text, match_expr, replace_expr)

동적 표현식의 예로, 다음 regexprep 명령은 internationalization이라는 용어를 해당 축약형인 i18n으로 올바르게 대체합니다. 그러나, globalization과 같은 다른 용어에 이 명령을 사용하려면 다음과 같이 다른 대체 표현식을 사용해야 합니다.

match_expr = '(^\w)(\w*)(\w$)';

replace_expr1 = '$118$3';
regexprep('internationalization', match_expr, replace_expr1)
ans =

    'i18n'
replace_expr2 = '$111$3';
regexprep('globalization', match_expr, replace_expr2)
ans =

    'g11n'

동적 표현식 ${num2str(length($2))}를 사용하면 입력 텍스트에 따라 대체 표현식을 조정할 수 있으므로 매번 표현식을 변경할 필요가 없습니다. 이 예제에서는 동적 대체 구문 ${cmd}를 사용합니다.

match_expr = '(^\w)(\w*)(\w$)';
replace_expr = '$1${num2str(length($2))}$3';

regexprep('internationalization', match_expr, replace_expr)
ans =

    'i18n'
regexprep('globalization', match_expr, replace_expr)
ans =

    'g11n'

구문 분석 시, 동적 표현식은 완전하고 유효한 정규 표현식과 일치해야 합니다. 또한, 백슬래시 이스케이프 문자(\)를 사용하는 동적 일치 표현식에는 두 개의 백슬래시가 필요합니다. 하나는 표현식의 초기 구문 분석에 필요하며, 다른 하나는 온전히 일치시키기 위해 필요합니다. 동적 표현식을 묶는 괄호는 캡처 그룹을 생성하지 않습니다.

다음 섹션에 설명된 바와 같이, 일치 표현식에 사용할 수 있는 세 가지 동적 표현식 형식과 대체 표현식에 사용할 수 있는 한 가지 형식이 있습니다.

동적 일치 표현식 — (??expr)

(??expr) 연산자는 표현식 expr을 구문 분석하고, 결과를 일치 표현식에 다시 삽입합니다. 그러면 MATLAB®이 수정된 일치 표현식을 실행합니다.

다음은 이 연산자와 함께 사용할 수 있는 표현식 유형을 보여주는 예제입니다.

chr = {'5XXXXX', '8XXXXXXXX', '1X'};
regexp(chr, '^(\d+)(??X{$1})$', 'match', 'once');

이 특정 명령의 용도는 입력 셀형 배열에 저장된 각 문자형 벡터에서 일련의 X 문자를 찾는 것입니다. 여기서 X의 개수가 문자형 벡터마다 다르다는 데 주의하십시오. 개수가 같은 경우에는 표현식 X{n}을 사용하여 n개의 해당 문자와 일치시킬 수 있을 것입니다. 그러나, 이 경우에는 상수 값 n으로 실행할 수 없습니다.

여기에 사용된 솔루션은 토큰에서 먼저 나온 개수(예: 셀형 배열의 첫 번째 문자형 벡터에서 5)를 캡처한 후 동적 표현식에서 그 개수를 사용하는 것입니다. 이 예제에 사용된 동적 표현식은 (??X{$1})이며, 여기서 $1은 토큰 \d+에 의해 캡처되는 값입니다. 연산자 {$1}은 해당 토큰 값의 수량자를 생성합니다. 표현식이 동적이기 때문에 동일한 패턴이 셀형 배열의 입력 벡터 3개 모두에서 작동합니다. 첫 번째 입력 문자형 벡터에서 regexp는 5개의 X 문자를 찾고, 두 번째에서는 8개, 세 번째에서는 한 개만 찾습니다.

regexp(chr, '^(\d+)(??X{$1})$', 'match', 'once')
ans =

  1×3 cell array

    {'5XXXXX'}    {'8XXXXXXXX'}    {'1X'}

일치 표현식을 수정하는 명령 — (??@cmd)

MATLAB은 MATLAB 명령의 결과를 일치 표현식에 포함시키기 위해 (??@cmd) 연산자를 사용합니다. 이 명령은 일치 표현식 내에 사용할 수 있는 용어를 반환해야 합니다.

예를 들어, 동적 표현식 (??@flilplr($1))을 사용하여 더 큰 문자형 벡터에 포함된 회문 "Never Odd or Even"을 찾아보겠습니다.

먼저, 입력 문자열을 생성합니다. 모든 문자가 소문자인지 확인하고, 단어가 아닌 문자는 모두 제거합니다.

chr = lower(...
  'Find the palindrome Never Odd or Even in this string');

chr = regexprep(chr, '\W*', '')
chr =

    'findthepalindromeneveroddoreveninthisstring'

다음과 같이 동적 표현식을 사용하여 문자형 벡터 내에서 회문을 찾습니다.

palindrome = regexp(chr, '(.{3,}).?(??@fliplr($1))', 'match')
palindrome =

  1×1 cell array

    {'neveroddoreven'}

동적 표현식은 문자형 벡터를 구성하는 문자의 순서를 역순으로 뒤집은 후, 순서가 뒤바뀐 벡터와 가능한 한 많이 일치시키려고 시도합니다. $1의 값이 토큰 (.{3,})의 값에 따라 달라지므로 여기에는 동적 표현식이 필요합니다.

MATLAB의 동적 표현식은 현재 활성화된 작업 공간에 액세스할 수 있습니다. 즉, 작업 공간에서 변수를 변경하여 동적 표현식에 사용된 함수나 변수를 변경할 수 있습니다. 위 예제에 나와 있는 마지막 명령을 반복하되, 이번에는 다음과 같이 기본 작업 공간에 저장된 함수 핸들을 사용하여 표현식 내에서 호출되는 함수를 정의합니다.

fun = @fliplr;

palindrome = regexp(chr, '(.{3,}).?(??@fun($1))', 'match')
palindrome =

  1×1 cell array

    {'neveroddoreven'}

함수 역할을 하는 명령 — (?@cmd)

(?@cmd) 연산자는 전체 일치 표현식을 구문 분석하는 동안 regexp 또는 regexprep가 실행해야 하는 MATLAB 명령을 지정합니다. MATLAB의 다른 동적 표현식과 달리, 이 연산자는 연산자가 사용된 표현식의 내용을 변경하지 않습니다. 대신, 이 기능을 사용하여 MATLAB에서 정규 표현식 중 하나의 내용을 구문 분석할 때 수행하는 단계가 무엇인지 보고하도록 할 수 있습니다. 이 기능은 정규 표현식을 진단하는 데 유용할 수 있습니다.

다음 예제에서는 0개 이상의 문자, 2개의 동일한 문자, 다시 0개 이상의 문자로 구성된 단어를 구문 분석합니다.

regexp('mississippi', '\w*(\w)\1\w*', 'match')
ans =

  1×1 cell array

    {'mississippi'}

MATLAB이 일치 항목을 확인하는 데 수행하는 정확한 단계를 추적하기 위해 이 예제에서는 간단한 스크립트 (?@disp($1))을 표현식에 삽입하여 최종적으로 일치 항목을 구성하는 문자를 표시합니다. 이 예제에서는 최대 일치(Greedy) 수량자를 사용하기 때문에, MATLAB은 가능한 한 많은 문자형 벡터를 일치시키려고 시도합니다. 따라서, MATLAB이 문자열의 시작 부분에서 일치 항목을 찾았어도 문자열 맨 끝에 도달할 때까지 추가 일치 항목을 계속해서 찾습니다. 문자열 맨 끝에서 역순으로 검색하여 문자 i, p와 다음 p를 찾고, 마침내 일치가 충족되므로 이 지점에서 일치 작업을 중지합니다.

regexp('mississippi', '\w*(\w)(?@disp($1))\1\w*', 'match')
i
p
p

ans =

  1×1 cell array

    {'mississippi'}

이번에는 첫 번째 수량자를 최소 일치(Lazy)(*?)로 지정하여 동일한 예제를 다시 시도해 보겠습니다. 이번에도 MATLAB은 동일한 일치 작업을 수행합니다.

regexp('mississippi', '\w*?(\w)\1\w*', 'match')
ans =

  1×1 cell array

    {'mississippi'}

그러나, 동적 스크립트를 삽입하면 이번에는 MATLAB이 완전히 다른 텍스트와 일치시켰음을 확인할 수 있습니다. 이 경우, MATLAB은 찾을 수 있는 가장 첫 번째 일치 항목을 사용하고, 나머지 텍스트는 고려하지 않습니다.

regexp('mississippi', '\w*?(\w)(?@disp($1))\1\w*', 'match')
m
i
s

ans =

  1×1 cell array

    {'mississippi'}

이 유형의 동적 표현식이 얼마나 유연한지 확인하기 위해, MATLAB이 입력 텍스트를 반복적으로 구문 분석하면서 이에 따라 셀형 배열을 점진적으로 조립해 나가는 다음 예제를 살펴보겠습니다. 표현식의 끝에 있는 (?!) 연산자는 실제로 빈 전방 탐색 연산자이므로, 각 반복마다 강제로 실패를 발생시킵니다. 이렇게 강제로 발생시키는 실패는 MATLAB이 표현식을 확인하는 데 수행하는 단계를 추적하려는 경우 반드시 필요합니다.

MATLAB은 입력 텍스트를 통과하는 여러 차례의 통과를 수행하면서 매번 다른 조합의 문자를 시도해 마지막 일치 항목보다 더 정확한 일치 항목이 있는지 확인합니다. 일치 항목이 없는 통과의 경우 테스트는 빈 문자형 벡터를 반환합니다. 동적 스크립트 (?@if(~isempty($&)))matches 셀형 배열에서 빈 문자형 벡터를 생략하는 데 사용됩니다.

matches = {};
expr = ['(Euler\s)?(Cauchy\s)?(Boole)?(?@if(~isempty($&)),' ...
   'matches{end+1}=$&;end)(?!)'];

regexp('Euler Cauchy Boole', expr);

matches
matches =

  1×6 cell array

    {'Euler Cauchy Bo…'}    {'Euler Cauchy '}    {'Euler '}    {'Cauchy Boole'}    {'Cauchy '}    {'Boole'}

연산자 $&(또는 이에 대응하는 $0), $`, $'는 입력 텍스트에서 현재 일치 항목에 해당하는 부분, 현재 일치 항목 앞에 있는 모든 문자, 현재 일치 항목 다음에 있는 모든 문자를 각각 나타냅니다. 때때로 이러한 연산자는 동적 표현식을 사용할 때, 특히 (?@cmd) 연산자를 포함하는 동적 표현식을 사용할 때 유용합니다.

이 예제에서는 입력 텍스트를 구문 분석하여 문자 g를 찾습니다. 각 텍스트 반복에서, regexp는 현재 문자를 g와 비교하고, 일치 항목이 없는 경우 다음 문자로 진행합니다. 이 예제에서는 구문 분석되는 현재 위치를 ^ 문자로 표시함으로써 텍스트 검색 작업의 진행 상황을 추적합니다.

$` 연산자는 텍스트에서 현재 구문 분석 중인 위치의 앞과 뒤에 있는 부분을 캡처합니다. 연속된 문자 가 텍스트 내에 있는 경우 이 시퀀스는 두 개의 작은따옴표($'')를 사용하여 표시해야 합니다.

chr = 'abcdefghij';
expr = '(?@disp(sprintf(''starting match: [%s^%s]'',$`,$'')))g';

regexp(chr, expr, 'once');
starting match: [^abcdefghij]
starting match: [a^bcdefghij]
starting match: [ab^cdefghij]
starting match: [abc^defghij]
starting match: [abcd^efghij]
starting match: [abcde^fghij]
starting match: [abcdef^ghij]

대체 표현식의 명령 — ${cmd}

${cmd} 연산자는 정규 표현식 대체 패턴의 내용을 수정하여, 이전 패턴과 달라질 수도 있는 입력 텍스트를 파라미터에 맞는 패턴으로 만들 수 있습니다. MATLAB에 사용되는 다른 동적 표현식과 같이, 전체 대체 표현식 내에 이러한 표현식을 원하는 만큼 포함시킬 수 있습니다.

대체 표현식의 명령은 변수의 로컬 작업 공간만 검사합니다. 호출자 작업 공간과 전역 작업 공간은 대체 표현식의 명령에 사용할 수 없습니다.

여기에 나와 있는 regexprep 호출에서 대체 패턴은 '${convertMe($1,$2)}'입니다. 이 경우, 전체 대체 패턴은 동적 표현식입니다.

regexprep('This highway is 125 miles long', ...
          '(\d+\.?\d*)\W(\w+)', '${convertMe($1,$2)}');

이 동적 표현식은 MATLAB에 convertMe라는 이름의 함수를 실행하도록 지시합니다. 이 함수는 두 개의 토큰 (\d+\.?\d*)(\w+)로 도출된 일치 텍스트를 convertMe 함수의 입력 인수로 사용합니다. $1$2의 값은 런타임 시 생성되므로 대체 패턴에는 동적 표현식이 필요합니다.

다음 예제에서는 convertMe라는 파일에 측정 단위를 영국식 단위에서 미터법 단위로 변환하는 함수를 정의합니다.

function valout  = convertMe(valin, units)
switch(units)
    case 'inches'
        fun = @(in)in .* 2.54;
        uout = 'centimeters';
    case 'miles'
        fun = @(mi)mi .* 1.6093;
        uout = 'kilometers';
    case 'pounds'
        fun = @(lb)lb .* 0.4536;
        uout = 'kilograms';
    case 'pints'
        fun = @(pt)pt .* 0.4731;
        uout = 'litres';
    case 'ounces'
        fun = @(oz)oz .* 28.35;
        uout = 'grams';
end
val = fun(str2num(valin));
valout = [num2str(val) ' ' uout];
end

명령줄에서 변환할 수량에 대한 값과 영국식 단위의 이름을 전달하여 regexprep에서 convertMe 함수를 호출합니다.

regexprep('This highway is 125 miles long', ...
          '(\d+\.?\d*)\W(\w+)', '${convertMe($1,$2)}')
ans =

    'This highway is 201.1625 kilometers long'
regexprep('This pitcher holds 2.5 pints of water', ...
          '(\d+\.?\d*)\W(\w+)', '${convertMe($1,$2)}')
ans =

    'This pitcher holds 1.1828 litres of water'
regexprep('This stone weighs about 10 pounds', ...
          '(\d+\.?\d*)\W(\w+)', '${convertMe($1,$2)}')
ans =

    'This stone weighs about 4.536 kilograms'

이전 섹션에서 설명한 (??@ ) 연산자와 같이 ${ } 연산자는 현재 활성화된 작업 공간의 변수에 액세스할 수 있습니다. 다음 regexprep 명령은 기본 작업 공간에 정의된 배열 A를 사용합니다.

A = magic(3)
A =

     8     1     6
     3     5     7
     4     9     2
regexprep('The columns of matrix _nam are _val', ...
          {'_nam', '_val'}, ...
          {'A', '${sprintf(''%d%d%d '', A)}'})
ans =

    'The columns of matrix A are 834 159 672'

참고 항목

| |

관련 항목