정규식 test 메서드 문제 해결

Jinny·2024년 1월 18일
1

문제해결

목록 보기
9/13

예약 관리 페이지에서 예약자의 이름이나 번호를 통해
검색할 수 있게 구현하기로 했다.

성명이나 휴대폰 번호의 경우, 예약 정보 속성이 다르기 때문에
다르게 필터링을 해줘야 한다.

❗ 문제점)

이름 - 번호 - 이름 - 번호 순으로 검색하면 잘 작동되나
이름 - 이름, 번호 - 번호 순으로 검색하면 잘 작동이 안된다.
➡️ 심지어 정규식 검사 조건에서 거짓이 나와 제대로 실행되지 않는다. 그러나 실제로 입력한 값은 정규식에 매칭이 되는 단어이다.

이상한 점은 조건문 밖에서 콘솔을 찍어보면 정규식 일치 여부는
으로 나오는데 조건식에 해당하는 코드 로직이 실행되지 않는다.

조건문 밖에 있는 콘솔 코드를 없애고 조건문 안에서 콘솔을 찍으면
검색 기능이 제대로 작동이 된다. 그리고 조건문 안에서 찍힌 콘솔에서는 정규식 일치 여부가 거짓으로 나온다.

  const handleSearch = () => {
    //아래 코드 작성하면 제대로 작동이 안됨. 
    //console.log('text', text, '정규식 일치 여부', NAME_REGEX.test(text));
    if (NAME_REGEX.test(text)) {
    //아래 코드 작성하면 제대로 작동이 됨. 
    //console.log('text', text, '정규식 일치 여부', NAME_REGEX.test(text));
      setResult(
        reservations?.filter((reservation) => reservation.client_name === text),
      );
    }

    if (PHONE_REGEX.test(text)) {
      if (text.length === 10) {
        const formatPhone = text.replace(/(\d{3})(\d{3})(\d{4})/, '$1-$2-$3');
        setResult(
          reservations?.filter(
            (reservation) => reservation.client_phone === formatPhone,
          ),
        );
      }

      if (text.length === 11) {
        const formatPhone = text.replace(/(\d{3})(\d{4})(\d{4})/, '$1-$2-$3');
        setResult(
          reservations?.filter(
            (reservation) => reservation.client_phone === formatPhone,
          ),
        );
      } else {
        setResult(
          reservations?.filter(
            (reservation) => reservation.client_phone === text,
          ),
        );
      }
    }
    //번호 형태면 동일한 번호로 불러오자 그냥..
    //searchReservation(text);
    setText('');
  };

문제점 확인

정규식에 전역 탐색 플래그(g)를 설정해서 검색할 때 마다
test 메서드를 실행하는데 매번 lastIndex 값이 업데이트 되기 때문이다.

RegExp.lastIndex : 정규식 객체가 해당 문자열과 일치하기 시작하는 인덱스 값 반환


  const handleSearch = () => {
    setIsSearch(true);
    console.log(NAME_REGEX.lastIndex); // 0
    // console.log('text', text, '정규식 여부', NAME_REGEX.test(text));
    if (NAME_REGEX.test(text)) {
      console.log(NAME_REGEX.lastIndex); //3
      // 아래 콘솔 코드를 넣으면 잘 작동 없애면 잘 작동 x
      // console.log('text', text, '정규식 여부22', NAME_REGEX.test(text));
      setResult(
        reservations?.filter((reservation) => reservation.client_name === text),
      );
    }
  };

조건문 밖과 안에서 콘솔을 찍어보면 lastIndex 값이 다르게
나오는 것을 확인할 수 있었다.

공식 문서를 찾아보니 전역 탐색 플러그를 설정한 경우, exec 메서드
또는 test 메서드로 일치하는 문자열 검색에 성공한 경우 lastIndex를 업데이트 한다고 나와있다.

💡 해결 방안

정규식에서 전역 플래그 g를 제거하거나 검색할 때 마다 lastIndex 값을 0으로 업데이트 해주면 된다.

나같은 경우는 꼭 전역 플래그를 설정할 필요는 없기 때문에 전역 플러그를 제거해주는 방식을 선택했다.

export const NAME_REGEX = /^[가-힣a-zA-Z]{2,16}$/;
export const PHONE_REGEX = /^01([0|1|6|7|8|9])-?([0-9]{3,4})-?([0-9]{4})$/;

➡️ 기존 정규식에서 전역 플래그를 제거하니 제대로 잘 작동이 되었다.

정규식 플래그 종류

FlagMeaningDescription
iIgnore Case대소문자를 구별하지 않고 검색
gGlobal문자열 내의 모든 패턴 검색
mMulti Line문자열의 행이 바뀌더라도 검색 계속함
s(모든 문자 정규식)이 개행 문자 \n이 포함하도록 설정
uunicode유니코드 전체를 지원
ysticky문자 내 특정 위치에서 검색을 진행하는 ‘sticky’ 모드를 활성화

정규식을 테스트할 때 당연히 g 플래그를 사용하는 것으로만
알고 있었는데 용도에 따라 다르다는 것을 알게되었다.

0개의 댓글