정규표현식, 긍정형 부정형 탐색

merci·2024년 4월 1일

백슬래시 이스케이프

백슬래시\ 는 특수 문자를 이스케이프하거나 특정 문자 클래스에 속하는 문자를 표현하는 데 사용된다

특수 문자 이스케이프

아래의 특수문자들을 정규검색으로 찾고 싶다면 \를 앞에 붙여서 이스케이프 처리를 해야한다

특수 문자의미
.개행 문자를 제외한 모든 단일 문자
*0회 이상 반복
+1회 이상 반복
?0 or 1회 반복
|or
()캡쳐 그룹 정의
[]문자 클래스 정의
{}횟수 or 범위 지정
^문자열의 시작
$문자열의 끝
\백슬래시는 \\로 사용한다


특별한 문자 클래스 표현

문자 클래스의미동일한 정규식
\d모든 숫자와 일치[0-9]
\D숫자가 아닌 모든 문자와 일치[^0-9]
\w모든 단어 문자(알파벳, 숫자 및 밑줄)와 일치[a-zA-Z0-9_]
\W단어 문자가 아닌 모든 문자와 일치[^a-zA-Z0-9_]
\s모든 공백 문자(스페이스, 탭, 줄바꿈 등)와 일치
\S공백 문자가 아닌 모든 문자와 일치
\b단어 경계를 의미. 단어 문자와 비단어 문자 사이의 위치와 일치
\B단어 경계가 아닌 위치와 일치



조합하면 아래와 같이 사용할 수 있다

정규표현식의미
\s+하나 이상의 공백 문자
\d?숫자가 없거나 한자리 수
[^abc]a,b,c를 제외한 모든 문자와 일치
[abc]a,b,c가 들어간 모든 문자와 일치
\s{3}공백 3칸
\d{2,}2자리 이상 숫자
\w{1,4}1~4자 문자



긍정형 탐색

(?=...)형식을 사용하며 ...에 찾고자 하는 패턴을 넣는다

  • 특정 단어 포함
Reg(?=Ex)

뒤에 Ex가 붙는 Reg를 찾는다. -> RegEx

  • 비밀번호 검색
^(?=.*\d).{8,}$

.* 어떤 문자가 0번 이상
.*\d 어떤 문자 0번 이상 + 숫자 1자리
^, $ 이 패턴으로 시작해서 끝나는 문자
.{8,} 모든 문자 8자리 이상
(?=.*\d) 문자열 어딘가에 숫자가 반드시 들어가야 한다

긍정형 후방 탐색

(?<...)형식을 사용한다.

(?<=Y)X

Y로 시작하는 X검색 -> YX

/(?<=\$)\d+/

$100 형식의 숫자를 찾는다


부정형 탐색

(?!...)형식을 사용하며 ...에 제외하고자 하는 패턴을 넣는다

  • 특정 단어 제외
file(?!\.exe)

뒤에 .exe가 붙지 않는 file을 찾는다 -> file.png or file.txt ...


^(?!.*\d).{8,}$

숫자를 포함하지 않는 8자리 이상 문자열

부정형 후방탐색

(?<!...)형식을 사용한다

(?<!\d)\w 앞에 숫자가 없는 문자를 검색
(?<!q)u 앞에 q가 없는 u를 검색
-> quack를 검색할 수 없다 = q(?!u)와 동일하다


정규표현식 검색

  • 확장자 검색
/\.txt$/


  • 전화번호 포맷 검증
/\(\d{3}\) \d{3}-\d{4}/
function isValidPhoneNumber(phoneNumber) {
    const regex = /\(\d{3}\) \d{3}-\d{4}/;
    return regex.test(phoneNumber);
}

console.log(isValidPhoneNumber("(123) 456-7890")); // true
console.log(isValidPhoneNumber("123-456-7890")); // false
console.log(isValidPhoneNumber("(123) 456-789")); // false


  • 비밀번호 조합 검증
/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[\*\+\(\)\{\}\[\]\.]).{8,}$/


  • <c:out value="" /> 이스케이프 처리가 필요한 곳 찾을 때
(?<!<c:out\s{1,5}escapeXml="true"\s+value=['"])(?<!<fmt:[^>]*)(?<!<c:set[^>]*)(?<!<codeUtils:[^>]*)(?<!items="[^"]*)(?<!test="[^"]*)(?<!<c:out\s{1,5}value=['"])(?<!<c:url\s{1,5}value=['"])\$\{(?![^}]*\b(codeManager|eq|empty|fn|ne)\b)([^}*\[\]<>+=\-]*\.[^}*\[\]<>+=\-]*)\}

(?<!<c:set[^>]*) -> <c:set ... > 내부를 검색에 포함하지 않음
\b(codeManager|eq|empty|fn|ne)\b는 파이프라인|으로 독립적인 단어들로 찾는다.
\b...\b를 사용해 각 단어들이 독립적으로 존재할 경우를 찾는다.
변경할 부분은 두번째 캡쳐 그룹을 사용 <c:out value="\${$2}" />

정규표현식 검색 시 *이나+가 들어간 검색은 성능이 좋지 않으므로 자세하게 검색하는게 좋다.

추가적으로 제외할 키워드를 추가한다면

(?<!style="[^"]*)(?<!id="[^"]*)(?<!for="[^"]*)(?<!class="[^"]*)
(?<!<script[^>]*)(?<!<tags:[^>]*)(?<!"javascript:[^"]*)(?<!'javascript:[^']*)
  • 간단히
(?<!<c:set[^>]*)(?<!style="[^"]*)(?<!id="[^"]*)(?<!name="[^"]*)(?<!for="[^"]*)(?<!class="[^"]*)(?<!<script[^>]*)(?<!<tags:[^>]*)(?<!<fmt:[^>]*)(?<!"javascript:[^"]*)(?<!'javascript:[^']*)(?<!test="[^"]*)(?<!items="[^"]*)(?<!<codeUtils:[^>]*)(?<!<c:out value=")(?<!<c:out value=')(?<!<c:out escapeXml="true" value="[^"])\$\{(?![^}]*\b(codeManager|eq|empty|fn|ne)\b)([^}*\[\]<>+=\-]*\.[^}*\[\]<>+=\-]*)\}

(참고)

<td class="" value" 여기서 이스케이프 처리  오류 발생 " >
<c:if test=" 여기서 이스케이프 처리 시 오류 발생 ">
<c:set ~ 여기서 이스케이프 처리  오류 발생 >



정규표현식 + replace

  • 캡쳐 그룹으로 형식 변경
let dateString = "2023-01-02";
let regex = /(\d{4})-(\d{2})-(\d{2})/;
let formattedDate = dateString.replace(regex, "$2/$3/$1");
console.log(formattedDate); // "01/02/2023"


  • xxx-xxx-xxx... 형태로 변경
    let regExpNum = /[^a-zA-Z0-9]/g;
    let regExpCiphers = /^(\w{0,3})(\w{0,3})(\w{0,6})$/g;
    let regExpHyphen = /(\-{1,2})$/g;

    elem.value = elem.value
      		.replace(regExpNum, '')
            .replace(regExpCiphers, "$1-$2-$3")
            .replace(regExpHyphen, "");

^(\w{0,3})(\w{0,3})(\w{0,6})$ 문자열을 3개의 캡쳐 그룹으로 나눈다. (문자열 최대 3자리, 3자리, 6자리)

^, $를 사용함으로써 세 그룹은 순서가 정해진다.
(\-{1,2})$ 는 문자열 끝에 1~2개의 -를 찾는다.
3개의 캡쳐 그룹은 '$1-$2-$3'의 모양으로 대체된다.
123abc456789 -> 123-abc-456789

    let $schInput = document.querySelector('#recMedia');
    let regExpNum = /[^0-9]/g;
    let regExpCiphers = /^(\d{0,7})(\d{0,4})(\d{0,2})(\d{0,3})(\d{0,1})(\d{0,6})$/g;
    let regExpHyphen = /(\-{1,5})$/g;

    $schInput.value = $schInput.value.replace(regExpNum, '')
                        .replace(regExpCiphers, "$1-$2-$3-$4-$5-$6")
                        .replace(regExpHyphen, "");


  • 1000단위 콤마 찍기
    function comma(str) {
        str = String(str);
        return str.replace(/(\d)(?=(?:\d{3})+(?!\d))/g, '$1,');
    }

첫번째 (\d)는 숫자를 찾아 첫번째 캡쳐 그룹을 형성
(?=(?:\d{3})+(?!\d)):
긍정형 전방 탐색을 사용해 현재 위치에서 오른쪽으로 적어도 한 번 이상 반복되는 세 자리 숫자 그룹\d{3}이 있지만 그 바로 다음에 숫자가 오지 않는(?!\d) 위치를 찾는다
?:는 천 단위 구분자가 필요한 위치를 찾기 위해 캡쳐하지 않는 그룹을 나타낸다

$1,: 대체 문자열, 첫 번째 캡쳐 그룹(\d)에 해당하는 숫자 뒤에 콤마를 추가


  • 콤마 제거
    function unComma(str) {
        str = String(str);
        return str.replace(/[^\d]+/g, '');
    }

/[^\d]+/g는 하나 이상의 숫자가 아닌 문자를 찾아서 제거한다


split

숫자를 기준으로 문자열 나누기: `split("\\d+")`
단어 문자가 아닌 문자를 기준으로 문자열 나누기: `split("\\W+")`
알파벳이 아닌 문자로 문자열 나누기: `split("[^a-zA-Z]")`
단어 경계를 기준으로 문자열 나누기: `split("\\b")`


특수문자 제거

// 특수문자, 괄호, 점, 공백 모두 제거
let reg = /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/ ]/gim;

// 특수문자, 괄호, 점 모두 제거 - 공백은 제거 안함
let reg = /[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gim;

//특수문자, 괄호, 공백 모두 제거 - 점은 제거 안함
let reg = /[`~!@#$%^&*()_|+\-=?;:'"<>\{\}\[\]\\\/ ]/gim;

//정규식에 해당하는 문자를 replace 로 제거
let resultData = originalData.replace(reg, "");
profile
작은것부터

0개의 댓글