728x90

Python 에서 정규표현식을 사용하여 문자열을 추출하는 법 예제 코드이다.

 

greedy 수량자와 non-greedy 수량자의 차이점을 확인할 수 있다.

import re
 
reg = re.search(r'a[bcd]*b''abcdccb')
print(reg)
 
reg = re.search(r'a[bcd]*?b''abcdccb')
print(reg)
 
reg = re.search(r'a[bcd]*?b''abbcdccb')
print(reg)
 
reg = re.search(r'a[bcd]*?c''abbcdccb')
print(reg)
 
reg = re.search(r'a[bcd]*c''abbcdccb')
print(reg)
 
reg = re.search(r'a[bcd]+?b''abcdccb')
print(reg)
 
reg = re.search(r'a[bcd]+?b''abbcdccb')
print(reg)
 

 

 

\w matches any word character ( alphanumeric plus "_" ).

import re
 
samples = [
    '서울시 강남구 대치동 123번지',
    '서울시 강동구 상일동 123번지 201동 501호',
    '서울시 강동구 천호4동 123번지 103동 208호',
    '서울시 강동구 길동 0412번지 0008호 마루빌딩 6층',
    '서울시 강동구 길동 412번지 8호 마루빌딩 6층 제103동, 제104동 새올',
]
# 다른 언어에서는 한글은 word 로 인식 하지 않기 때문에 \b 로 구분할 수 없다.
for i in samples:
    # findall : 문자열의 전체를 검색 (결과 : 문자열 리스트)
    print(re.findall("(?:.+[도시]\s)(?:.+[시구]\s)(.+동)\s",i)[0])
    print(re.findall("(?:.+[도시]\s)(?:.+[시구]\s)(.+?동)\s",i)[0])
    # ?: : 그룹핑 대상에서 제외하라.
    # [도시] : 도 or 시
    # \s : 공백
    # .+ : 임의의 문자(.)를 + (1개 이상 반복) 동 글자를 만나는 문장 끝까지
    # .+? : 임의의 문자(.)를 +?(1개 이상 반복) 동 글자를 만나는 문장 첫글자까지
 
print('-'*10)
 
# Python 과 .NET(C#) 에서는 한글, 영문, 숫자, 언더바(_)를 word 로 인식하는 것 같다.
for i in samples:
    print(re.findall("(\w+?동)\s",i)[0])
 

 

 

https://regex101.com/ 에서 검증을 해보시라.

 

728x90
블로그 이미지

Link2Me

,
728x90

PHP 로 정규표현식 문자열 추출하는 것을 다양한 예제를 통해서 알아본다.

잘못 파싱할 수 있는 오류를 방지하기 위해 아래 예제를 하나 하나 실행해 보시라.

아직 정규표현식을 완전히 마스터하지 못해서 처리하는 수준이 미약함.

 

문자열을 복사하여 https://regexr.com/ 에 붙여넣고 정규표현식을 육안으로 확인해보면 도움이 많이 된다.

 

읍면동 앞까지의 주소 추출하는 정규표현식

<?php
 
$str = "서울시 강동구 명일동 123번지 101동 702호";
if(strpos($str'동'!== false ){
    // (abc) : capture group
    // (?:abc) : non-capturing group (그룹으로 결과를 반환하지 말라)
    preg_match('/(.+?)[읍면동]\s/'$str,$out);
    echo trim($out[0]).'<br />';
}
 
?>

.+  와  .+? 의 차이점을 이해하면 원하는 걸 얻을 수 있다.

 

<?php
ini_set("display_startup_errors"1);
ini_set("display_errors"1);
error_reporting(E_ALL);
 
 
$str = "서울시 강동구 명일동 123번지 101동 702호";
if(strpos($str'동'!== false ){
    $stArr = explode(" "$str);
    foreach($stArr as $item){
        if(strpos($item'동'!== false ){
            echo $item.'<br />';
            // 원하는 결과를 반환하고 있는가?
        }
    }
echo '-----------------------------------------------<br/>';
 
// \b(word boundary) 는 영문자와 숫자는 포함되지만 한글은 포함되지 않는다.
// word는 한글과 같은 2바이트 문자를 포함하지 않기 때문에, 한글의 경계는 \b로 처리할 수 없다.
$str = "Hello, Java!";
preg_match('/\bJava\b/'$str,$out);
if(count($out)>0){
    // 그룹으로 묶지 않아서 일치하면 1개만 반환
    echo $out[0].'<br/>';
}
 
$str = "Hello, Java!";
preg_match('/\b(Java)\b/'$str,$out);
if(count($out)>0){
    // 그룹()으로 묶어서 일치하면 2개 반환
    echo '<pre>';print_r($out);echo '</pre>';
}
 
$str = "서울시 강남구 대치동 123번지";
if(strpos($str'동'!== false ){
    preg_match('/\b대치동\b/'$str,$out);
    if(count($out)>0){
        echo $out[0].'<br/>';
    } else {
        echo '추출 못함<br/>';
    }
}
 
 
$str = "서울시 강남구 대치동 123번지"
$str = "서울시 강동구 명일동 123번지 101동 702호"// 101동을 반환
if(strpos($str'동'!== false ){
    // (abc) : capture group
    // (?:abc) : non-capturing group (그룹으로 결과를 반환하지 말라)
    preg_match('/(?:.+)\s(.+)동/'$str,$out);
    echo '<pre>';print_r($out);echo '</pre>';
}
 
$str = "서울시 강동구 상일동 123번지 201동 501호"
if(strpos($str'동'!== false ){
    // (abc) : capture group
    // (?:abc) : non-capturing group (그룹으로 결과를 반환하지 말라)
    // 숫자로 시작하는 동은 대상에서 제외.
    preg_match('/(?:.+)\s([^0-9]+)동/'$str,$out);
    echo '<pre>';print_r($out);echo '</pre>';
}
 
// 공백으로 문자열을 분리하여 동이 들어간 문자열 반환
$str = "서울시 강동구 천호동 123번지 103동 208호";
if(strpos($str'동'!== false ){
    $stArr = explode(" "$str);
    foreach($stArr as $item){
        if(preg_match('/(.*)동$/'$item)){
            // 문자열의 끝($)이 동으로 끝나는 것만 반환하라.
            preg_match('/(.*)동$/'$item$out);
            echo '<pre>';print_r($out);echo '</pre>';
        }
    }
}
 
$str = "서울시 강동구 천호4동 123번지 103동 208호";
if(strpos($str'동'!== false ){
    $stArr = explode(" "$str);
    foreach($stArr as $item){
        if(preg_match('/(^[^0-9]{1,1}.+)동$/'$item)){
            preg_match('/(.*)동$/'$item$out);
            echo '<pre>';print_r($out);echo '</pre>';
        }
    }
}
 
?>
 

 

 

<?php
/*  정규표현식 문자 추출 예제 */
$str = "서울시 강동구 상일2동 123번지 201동 501호"
//$str = "서울시 강남구 대치2동 123번지"; 
echo getDongName($str);
echo '<br />';
 
function getDongName($str){
    if(strpos($str'동'!== false ){
        // (abc) : capture group
        // (?:abc) : non-capturing group (그룹으로 결과를 반환하지 말라)
        // 숫자로 시작하는 동은 대상에서 제외.
        preg_match('/(?:.+)\s([^0-9]{1,1}.+)동/'$str,$out);
        if(preg_match('/[^0-9]{1,1}.+동/'$out[1])){
            preg_match('/([^0-9]{1,1}.+)동/'$out[1],$rs);
            return $rs[1];
        } else {
            return $out[1];
        }
    }
}
?>

 

<?php
// .*? : lazy quantifier
$str = "서울시 강동구 길2동 123번지 103동 208호";
if(strpos($str'동'!== false ){
    preg_match('/(?:.+[도시]\s)(?:.+[시구]\s)(.+?)동/'$str$out);
    echo '<pre>';print_r($out);echo '</pre>';
}
 
$str = "서울시 강동구 천호3동 654번지 303동 502호";
if(strpos($str'동'!== false ){
    $out = preg_replace('/(?:.+[도시]\s)(?:.+[시구]\s)([^0-9]{1}.*?)동(?:\s.+)/',"\\1" ,$str);
    echo '<pre>';print_r($out);echo '</pre>';
}
 
$str = "서울시 강동구 천호2동 888번지 803동 502호";
if(strpos($str'동'!== false ){
    $out = preg_replace('/(?:.+[도시]\s)(?:.+[시구]\s)([^0-9]{1}.*?)동(?:\s.+)/',"$1" ,$str);
    echo '<pre>';print_r($out);echo '</pre>';
}
?>
 

 

728x90
블로그 이미지

Link2Me

,
728x90

파이썬은 정규 표현식을 지원하기 위해 re(regular expression의 약어) 모듈을 제공한다.

re 모듈은 파이썬을 설치할 때 자동으로 설치되는 기본 라이브러리이다.

import re
 
str = 'love people around you, love your work, love yourself'
 
# 1) match : 문자열의 처음부터 정규식과 매치되는지 조사 (결과 : 1개의 match 객체)
# 문자열의 처음에 일치하는 문자열이 없으면 None 반환
result0 = re.match('love'str)
print(result0)

result1 = re.match('people'str)
print(result1)

# 2) search : 문자열의 전체를 검색하여 정규식과 매치되는지 조사 (결과 : 1개의 match 객체)
result = re.search('people'str)
print(result)
 
# 2.1) group() : 매칭된 문자열을 반환
print("matched string : {}".format(result0.group()))
print("matched string : {}".format(result.group()))
 
# 2.2) start() : 매칭된 문자열의 시작 위치 반환
print(result.start())
 
# 2.3) end() : 매칭된 문자열의 끝 위치 반환
print(result.end())
 
# 2.4) span() : 매칭된 문자열의 (시작, 끝) 위치 튜플을 반환
print(result.span())
 
 
# 3) findall : 문자열의 전체를 검색 (결과 : 문자열 리스트)
# search 가 최초로 매칭되는 패턴만 반환한다면, findall은 매칭되는 전체의 패턴을 반환
# https://link2me.tistory.com/2129 에서 제대로 된 예제 확인 가능
rst_all = re.findall('love'str)
print(rst_all)
 
# 4) finditer : 문자열의 전체를 검색 (결과 : match 객체 iterator)
results = re.finditer('love'str)
print(results)
 
for result in results:
    print(result)
 
# 5) fullmatch 패턴과 문자열이 완벽하게 일치하는지 검사
str2 = 'Hey Guys, read books'
result = re.fullmatch('.*', str2)
print(result)
 
# 1. Group 그룹
# 1) 매칭되는 문자열 1개
str1 = '010-1112-6780'
result = re.match('\d{2,3}-\d{3,4}-(\d{4})$', str1)
print(result.group(1))
 
# 2) 매칭되는 문자열 여러개
str2 = '010-2343-7888,010-2343-1234,010-2343-5678,010-2343-9999,010-2343-2222'
results = re.finditer('\d{2,3}-\d{3,4}-(\d{4})(?=,|$)', str2)
# (?=,|$) : 전방탐색 , 기준으로 전방탐색, 문자열 마지막($) 기준으로 전방탐색

for idx, result in enumerate(results, 1):
    print(f'{idx}. {result.group(1)}')
 
 
# 2. Substitution (교체) - 전화번호 마스킹 처리
# sub : 주어진 문자열에서 일치하는 모든 패턴을 replace
# 그 결과를 문자열로 다시 반환함.
# 두번째 인자는 특정 문자열이 될 수도 있고, 함수가 될 수도 있음.
# count가 0인 경우는 전체를 치환하고, 1이상이면 해당 숫자만큼 치환 됨.
str3 = '010-1113-5680'
후방탐색 : ?<=
result = re.sub('(?<=\d{3}-\d{4}-)\d{4}''****', str3)
print(result)
 
result = re.sub('(?<=\d{3}-\d{2})\d{2}-\d{2}''**-**', str3)
print(result)
 

 

import re
 
# compile
# 동일한 정규표현식을 매번 다시 쓰기 번거로움을 해결
# compile로 해당 표현식을 re.RegexObject 객체로 저장하여 사용 가능
 
email_regex = re.compile("([A-Za-z]+[A-Za-z0-9]+@[A-Za-z]+\.[A-Za-z]+)")
# email_regex = re.compile("(\.)")
email_input = input("이메일 입력 : ")
email_validation = email_regex.search(email_input.replace(" ",""))
 
if email_validation:
    print("It's vaild")
else:
    print("It's invaild")
728x90
블로그 이미지

Link2Me

,
728x90

 

플래그는 아래와 같은 종류가 있다.

i Ignore Case 대소문자를 구별하지 않고 검색한다.
g Global 문자열 내의 모든 패턴을 검색한다.
m Multi Line 문자열의 행이 바뀌더라도 검색을 계속한다.

 

 

숫자를 누르면 값을 추출하는 것은 curPage = $(this).text(); 로 해결된다.

▷ 의 값을 추출하는 것은 인접값 + 1 로 추출하면 된다.

curPage=parseInt($(this).prev().text()) + 1;

 

하지만 맨 마지막 페이지(▶)의 값을 추출하는 것은 위와 같은 방법으로는 해결이 되지 않는다.

PHP 와 연동된 html 소스보기를 해서 보면

<a class="page-link" href="Customer.php?p=206&m=list">7969</a>

와 같다.

 

그래서 curPage=$(this).find('a.page-link').attr('href').replace(/[^0-9]/g,''); 로 코드를 구현했다.

검색어를 넣지 않았을 때는 문제가 없는데, 검색어를 넣으면

<a class="page-link" href="Customer.php?p=206&m=list&where=name&keyword=%EC%9D%B4%EC%95%A4%EC%94%A8">206</a>

keyword 에 포함된 숫자값을 몽땅 다 반환하여 원하는 206의 값이 아니라 완전 엉뚱한 값을 반환하더라.

 

원하는 값을 추출하기 위해서는 필요한 값 주위를 먼저 제거하는 방식으로 처리했다.

https://regexr.com/ 사이트에서 내가 원하는 정규표현식 값이 추출되는지 확인한다.

 

후방탐색 정규표현식을 사용하여 원하는 값을 찾아낸다.

(?<=ABC) → 후방탐색(Positive lookbehind) : 해당 문자열(ABC)을 기준으로 뒷부분을 찾는다.

/(?<=\&m\=).+/g 를 하면 &m= 뒷부분을 전부 찾아준다.

 

curPage=$(this).find('a.page-link').attr('href').replace(/(?<=\&m\=).+/g,'');

로 해서 뒷부분 코드를 제거한다.

 

전방탐색 정규표현식 (?=ABC) 을 사용하여 앞부분 문자열을 제거한다.

/.+(?=\?p\=)/g

curPage=$(this).find('a.page-link').attr('href').replace(/(?<=\&m\=).+/g,'').replace(/.+(?=\?p\=)/g,'');

 

이렇게 하면 Customer2.php 라고 앞부분에 숫자가 들어가도 문제가 되지 않는다.

이제 마지막으로 숫자만 남기고 제거를 한다.

curPage=$(this).find('a.page-link').attr('href').replace(/(?<=\&m\=).+/g,'').replace(/.+(?=\?p\=)/g,'').replace(/[^0-9]/g,'');

 

 

전방탐색 및 후방탐색을 한꺼번에 사용해서 원하는 문자열만 추출해보자.

exec 메소드에서 반환하는 값은 일치하는 문자열의 배열이고 이 배열의 첫 번째 원소는 패턴에 일치하는 문자열이 된다. 

curPage=/(?<=\?p\=)(.+)(?=\&m\=)/.exec($(this).find('a.page-link').attr('href'))[0];

로 하면 간단하게 해결이 된다.

iOS 에서 문제가 발생하더라. Android 와 PC 크롬브라우저에서는 아무런 문제가 없다.

iOS에서 게시글 내용 출력 자체가 안되는 현상이 발생했다. 원인 파악하기 힘들어 엄청난 삽질 후, iOS Javascript는 전방탐색 기능만 지원하고 후방탐색 기능은 전혀 지원하지 못하더라.

curPage=$(this).find('a.page-link').attr('href').replace(/.+(?=\?p\=)/g,'').replace(/\D+(?=&m=)/g,'').replace(/[^0-9]/g,'');

또는

curPage=$(this).find('a.page-link').attr('href').match(/\d+(?=&m=)/g);

로 해결했다.

 

<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
 
const htmlString = $.trim($('.act').html());
console.log(htmlString);
 
const shref = $('.act').find('a.page-link').attr('href');
console.log(shref);
 
// exec 메소드에서 반환하는 값은 일치하는 문자열의 배열이고 이 배열의 첫 번째 원소는 패턴에 일치하는 문자열이 된다.
// 전방탐색과 후방탐색을 동시에 적용하여 원하는 문자열만 추출한다.
const hvar = /(?<=\?p\=)([\d]+)(?=\&m\=)/.exec($('.act').find('a.page-link').attr('href'))[0];
console.log(hvar);
 
// 전방탐색을 하면서 원하는 결과를 얻는다.
const curPage = $('.act').find('a.page-link').attr('href').match(/\d+(?=&m=)/g);
console.log(curPage);
 
// 천단위 콤마찍기
const a = "10000000";
const b = a.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
console.log(b); // 10,000,000
 
const stringVal = '2021-08-09';
console.log(stringVal.replace(/-/gi,'')); //결과 : 20210809
 
// slice ( 시작 문자열 순서, 문자열 갯수)
console.log(stringVal.slice(0,2)); // 결과 : 20
 
// 시작 문자열 순서만 넣으면, 시작 문자부터 끝 문자까지 문자 반환
console.log(stringVal.slice(2)); // 결과 : 21-08-09
 
// 시작 문자열 순서를 0보다 작게 넣으면, 문자의 끝에서 파라미터 만큼 앞으로 돌아가서 끝문자까지 반환
console.log(stringVal.slice(-2)); // 결과 : 09
 
// 이메일 형식에 맞는지 검사한다.
const email = 'jsk005.charlie@gmail.com';
const regexr = /^[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*@[0-9a-zA-Z]([-_\.]?[0-9a-zA-Z])*\.[a-zA-Z]{2,3}$/;
console.log(regexr.test(email)); // true
 
});
</script>
</head>
<body>
<div id="paging">
<ul class="pagination">
    <li class="page-item">
        <a class="page-link" href="Customer.php?p=1&amp;m=list&amp;where=name&amp;keyword=%EC%9D%B4%EC%95%A4%EC%94%A8&amp;">1</a>
    </li> 
    <li class="page-item">
        <a class="page-link" href="Customer.php?p=2&amp;m=list&amp;where=name&amp;keyword=%EC%9D%B4%EC%95%A4%EC%94%A8&amp;">2</a>
    </li> 
    <li class="page-item">
        <a class="page-link" href="Customer.php?p=3&amp;m=list&amp;where=name&amp;keyword=%EC%9D%B4%EC%95%A4%EC%94%A8&amp;">3</a>
    </li> 
    <li class="page-item">
        <a class="page-link" href="Customer.php?p=4&amp;m=list&amp;where=name&amp;keyword=%EC%9D%B4%EC%95%A4%EC%94%A8&amp;">4</a>
    </li> 
    <li class="page-item">
        <a class="page-link" href="Customer.php?p=5&amp;m=list&amp;where=name&amp;keyword=%EC%9D%B4%EC%95%A4%EC%94%A8&amp;">5</a>
    </li> 
    <li class="page-item">
        <a class="page-link" href="Customer.php?p=11&amp;m=list&amp;where=name&amp;keyword=%EC%9D%B4%EC%95%A4%EC%94%A8&amp;"></a>
    </li> 
    <li class="act">
        <a class="page-link" href="Customer.php?p=206&amp;m=list&amp;where=name&amp;keyword=%EC%9D%B4%EC%95%A4%EC%94%A8&amp;"><span style="color:red;"></span></a>
    </li> 
</ul>
</div>
 
</body>
</html>
 
 

 

728x90
블로그 이미지

Link2Me

,
728x90

Java에서 MAC 주소를 추출할 일이 생겼다.

기존 로직에 문제가 있을 수도 있게다 싶어 검색하고 좀 더 나은 로직을 적용해봤다.

 

import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class MacAddressRegex {
    /**
     * 문자열에서  패턴에 맞는 문자열 즉 맥주소를 뽑아낸다.
     * @param text 검사할 문자열
     * @return 맥 주소
     */
    public static String ParseMacAddress(String text) {
        String result = null;
        String[] list = text.split("\\p{XDigit}{2}(-\\p{XDigit}{2}){5}");
        int index = 0;
        for (String str : list) {
            if (str.length() < text.length()) {
                index = str.length();
                result = text.substring(index, index + 17);
                if (!result.equals("00-00-00-00-00-00")) {
                    break;
                }
                text = text.substring(index + 17);
 
            }
        }
        return result;
    }
 
    public static boolean macValidate(String mac) {
        Pattern p = Pattern.compile("^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$");
        Matcher m = p.matcher(mac);
        return m.matches();
    }
 
    private static final String PATTERN = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$";
    public static void main(String[] args) {
 
        System.out.println("MAC ADDRESS 00:00:00:00:AB:BC "+macValidate("00:00:00:00:AB:BC"));
        System.out.println("MAC ADDRESS 00:00:00:EF:AB:BC "+macValidate("00:00:00:EF:AB:BC"));
        System.out.println("MAC ADDRESS 00:00:DE:EF:AB:BC "+macValidate("00:00:DE:EF:AB:BC"));
        System.out.println("MAC ADDRESS 00:GH:DE:EF:AB:BC "+macValidate("00:GH:DE:EF:AB:BC"));
        System.out.println("MAC ADDRESS 0a:02:00:00:AB:BC "+macValidate("0a:02:00:00:AB:BC"));
        System.out.println("MAC ADDRESS 0A-00-27-00-00-11 "+macValidate("0A-00-27-00-00-11"));
        System.out.println("MAC ADDRESS 18-C0-4D-DB-26-67 "+macValidate("18-C0-4D-DB-26-67"));
 
        String str = "fhind18-C0-4D-DB-26-67dkdd";
        str = "DSz00:1E:AE:4F:20:0BDntl3l";
        String macaddress = ParseMacAddress(str); // 없으면 null 을 반환한다.
        if(macaddress != null && macaddress.length() == 17){
            System.out.println(macaddress);
        } else {
            System.out.println("문자열에 MAC 주소가 없어요.");
        }
    }
}
 

 

정규표현식 웹사이트 https://regexr.com/ 에서 직접 검증을 해볼 수 있다.

 

728x90
블로그 이미지

Link2Me

,
728x90

정규표현식에서 원하는 문자열만 찾아내고 싶을 때 후방탐색으로 특정문자열 뒷부분을 찾고, 전방탐색으로 특정문자열 앞부분을 찾는다.

(?<=문자열)

(?=문자열)

<?php
$str = "https://link2me.tistory.com/1100";
preg_match_all("/(?<=\/\/).+(?=\/)/" ,$str,$out);
echo '<pre>';print_r($out[0]);echo '</pre>';
 
preg_match_all("/.+(?=\/)/" ,$str,$out);
echo '<pre>';print_r($out[0]);echo '</pre>';
 
/*
 
(?<=ABC) → 후방탐색(Positive lookbehind) : 해당 문자열(ABC)을 기준으로 뒷부분을 찾는다.
 여기서는 // 를 기준으로 뒷부분을 찾아라.
 
(?=ABC) → 전방탐색(Positive lookahead) : 해당 문자열(ABC)을 기준으로 앞부분을 찾는다.
 여기서는 /를 기준으로 앞부분을 찾아라.
 
[] : 대괄호 사이에 존재하는 문자들중 하나에 일치
+ : 1개 이상
* : 0 개 이상 
? : 0 또는 하나
 
*/
 
$str = "https://link2me.tistory.com/dosomething.php?name=bar&shop=shirt";
preg_match_all("/(?<=\?)([-\w]+=[-\w]+&?)+/" ,$str,$out);
echo '<pre>';print_r($out[0]);echo '</pre>';
 
/*
? 기준으로 뒷부분을 찾아라. '변수명=값' 영역
w : 영문자, 숫자, _, 기타 스크립트 문자
 
*/
?>

 

특정 문자열 부분만 발췌하여 삭제하고 싶다면...

https://regexr.com/ 에서 원하는 정규표현식인지 검증하면서 확인하면 된다.

 

"/(?<=\s)(\([\d]+\))+/" : 공백 뒷부분에서 (숫자)로 된 부분만 찾아내라.

 

<?php
$str = "(한글) (영어) (121) 제목";
preg_match_all("/(?<=\s)(\([\d]+\))+/" ,$str,$out);
echo '<pre>';print_r($out[0]);echo '</pre>';
 
$out = preg_replace("/(?<=\s)(\([\d]+\))+/","",$str);
$out = preg_replace("/\s{2,}/"," ",$out);
echo $out.'<br/>';
 
/*
 
(?<=ABC) → 후방탐색(Positive lookbehind) : 해당 문자열(ABC)을 기준으로 뒷부분을 찾는다.
 여기서는 // 를 기준으로 뒷부분을 찾아라.
 
(?=ABC) → 전방탐색(Positive lookahead) : 해당 문자열(ABC)을 기준으로 앞부분을 찾는다.
 여기서는 /를 기준으로 앞부분을 찾아라.
 
() : ()안에 있는 문자들의 그룹화
[] : 대괄호 사이에 존재하는 문자들중 하나에 일치
+ : 1개 이상
* : 0 개 이상 
? : 0 또는 하나
 
그룹의 값 사용(\1, \2, …)
 
*/
 
$str = "I paid $30 for 50 apples.";
preg_match_all("/\b(?<!\$)[\d]+\b/" ,$str,$out);
echo '<pre>';print_r($out[0]);echo '</pre>';
 
// https://regexr.com/ 에서 테스트한 결과와 다르게 정확한 결과를 반환하지 못하는 거 같다.
?>
 

 

/[^>]*/ 는 '>' 을 제외한 *모든 것

 

728x90
블로그 이미지

Link2Me

,
728x90

보안 목적상 코드를 마스킹처리해야 한다. 일부는 정규표현식을 사용했다.

<?php
// ######### 마스킹 처리 ###########
function phoneNoMasking($str){ // 휴대폰번호 마스킹 처리
    $str = str_replace('-','',$str);
    $strlen = mb_strlen($str'utf-8');
    $mValue = "";
 
    switch($strlen){
        case 10:
            $mValue = mb_substr($str,0,3)."-".mb_substr($str,3,1)."**"."-*".mb_substr($str,7,3);;
            break;
        case 11:
            $mValue = mb_substr($str,0,3)."-".mb_substr($str,3,2)."**"."-*".mb_substr($str,8,3);
            break;
        case 0:
            $mValue ='';
            break;
    }
    return $mValue;
}
 
function IDMasking($str){ // id 마스킹
    $mValue = preg_replace('/.{3}$/''***'$str);
    return $mValue;
}
 
function EmailMasking($str){ // 수정 보완 필요
    //$str = preg_replace('/(?:^|@).\K|\.[^@]*$(*SKIP)(*F)|.(?=.*?\.)/', '*', $str);
    $pattern = '/(\w+)(\w{3})(@.{1})(?=.*?\.)(.+)/i';
    $replace = '\1***\3*\5';
    //$str = preg_replace('/(\w+)(\w{3})@(\w+)/i','\1***@\3',$str);
    $str = preg_replace('/(\w+)(\w{3})(@.{1})([\w*?]+)(.+)/i','\1***\3*\5',$str);
    return $str;
}
 
function IPaddressMasking($str){
    // ? : 0 ~ 1, + : 1개 이상
    $str = preg_replace('/(\d+)([\.]\d+[\.])(\d+)([\.]\d+)/i','***\2***\4',$str);
    return $str;
}
 
function DeviceIDMasking($str){ // 휴대폰 기기번호 전부 마스킹 처리
    $mValue = preg_replace('/(.*?)/''*'$str);
    return $mValue;
}
 
function letterMasking($str){ // 문자열 마스킹 : 홍*동
    $str = str_replace('-','',$str);
    $strlen = mb_strlen($str'utf-8');
    $mValue = "";
 
    switch($strlen){
        case 2:
            $mValue = mb_strcut($str03"UTF-8").'*';
            break;
        case 3:
            $mValue = mb_strcut($str03"UTF-8").'*'.mb_strcut($str811"UTF-8");
            break;
        case 4:
            $mValue = mb_strcut($str03"UTF-8").'**'.mb_strcut($str1215"UTF-8");
            break;
        default:
            $mValue = mb_strcut($str03"UTF-8").'**'.mb_strcut($str1215"UTF-8");
            break;
    }
    return $mValue;
}
 
?>

 

728x90
블로그 이미지

Link2Me

,
728x90

특정값 범위를 만족하는지 검사하는 예제로 지식인에 초보 답변 달았던 내용이다.

 

<?php
$num = 254// 55 ~ 255 사이인지 검사방법
if(preg_match("/(^5[5-9]$|^[6-9]{1}[0-9]{1}$|^[1-2]{1}[0-4]{1}[0-9]{1}$|^25[0-5]$)/",$num)){
    echo $num.'<br />';
else {
    echo 'The number is out of range.<br />';
}
 
/* // 설명
^ : 문자열의 시작
$ : 문자열의 끝
[] : 대괄호 사이에 존재하는 문자들중 하나에 일치
{} : 반복횟수
| :  OR
 
55 ~ 99 : 55 ~ 59, 60 ~ 99 로 분리해서 접근하면 ^5[5-9]$|^[6-9]{1}[0-9]{1}$
100 ~ 249 : 백의 자리는 1~2, 십의 자리는 0 ~ 4, 1의 자리는 0~9  ==> ^[1-2]{1}[0-4]{1}[0-9]{1}$
*/
?>

 

728x90
블로그 이미지

Link2Me

,
728x90

전화번호가 연속으로 두개가 한 셀에 있을 때 앞번호 1개만 추출하고, 전화번호와 이름이 혼용되어 있을 때 전화번호만 추출하고 싶을 때가 있다.

<?php
$line07 = "011-0001-0800, 010-0001-2981";
$mtelNO = TelNumRegex($line07);
echo preg_replace("/([0-9]{3})([0-9]{3,4})([0-9]{4})$/""\\1-\\2-\\3"$mtelNO);
echo '<br/><br/>';
 
$line07 = "홍길동 011-0002-0800";
$mtelNO = TelNumRegex($line07);
echo preg_replace("/([0-9]{3})([0-9]{3,4})([0-9]{4})$/""\\1-\\2-\\3"$mtelNO);
echo '<br/><br/>';
 
// 전화번호 정규식 반환 (전화번호 2개가 콤마로 구분되면 앞번호만 추출, 전화번호/성명 혼용이면 전화반호만 추출)
function TelNumRegex($inputNO){
    $pattern = '/\d{3}[-]?\d{4}[-]?\d{4}\s?[,]\s?\d{3}[-]?\d{4}[-]?\d{4}/';
    preg_match_all($pattern,$inputNO,$output);
    if(!empty($output[0])) {
        $tempNO = explode(',',$output[0][0]);
        $mtelNO = preg_replace("/[^0-9]/"""$tempNO[0]);
    } else {
        $mtelNO = preg_replace("/[^0-9]/"""$inputNO);
    }
    return $mtelNO;
}
 
?>
 

패턴 만들기는 https://regexr.com/ 사이트에서 테스트하면서 검증하면 된다.

 

위의 코드를 다시 수정해서 휴대폰번호만 추출하고, 개수를 여러개 반환하거나 1개만 반환한다는 가정하에 만든 코드이다.

<?php
$line07 = "011-0001-0800, 010-0001-2981";
$mtelNO = TelNumRegex($line07);
echo preg_replace("/([0-9]{3})([0-9]{3,4})([0-9]{4})$/""\\1-\\2-\\3"$mtelNO);
echo '<br/><br/>';
 
$line07 = "홍길동 011-0002-0800";
$mtelNO = TelNumRegex($line07);
echo preg_replace("/([0-9]{3})([0-9]{3,4})([0-9]{4})$/""\\1-\\2-\\3"$mtelNO);
echo '<br/><br/>';
 
// 전화번호 정규식 반환 (전화번호 2개가 콤마로 구분되면 앞번호만 추출, 전화번호/성명 혼용이면 전화반호만 추출)
function TelNumRegex($inputNO){
    $pattern = '/01[01679][-]?\d{4}[-]?\d{4}/';
    preg_match_all($pattern,$inputNO,$output);
    //echo '<pre>';print_r($output[0]);echo '</pre>';
    $mtelNO = preg_replace("/[^0-9]/"""$output[0][0]);
    return $mtelNO;
}
 
?>
 

 

 

728x90
블로그 이미지

Link2Me

,
728x90

<?php

$num = 254; // 55 ~ 255 사이인지 검사방법
if(preg_match("/(^5[5-9]$|^[6-9]{1}[0-9]{1}$|^[1-2]{1}[0-4]{1}[0-9]{1}$|^25[0-5]$)/",$num)){
    echo $num.'<br />';
} else {
    echo 'The number is out of range.<br />';
}

?>


^ : 문자열의 시작
$ : 문자열의 끝
[] : 대괄호 사이에 존재하는 문자들중 하나에 일치
{} : 반복횟수
| :  OR

55 ~ 99 : 55 ~ 59, 60 ~ 99 로 분리해서 접근하면 ^5[5-9]$|^[6-9]{1}[0-9]{1}$
100 ~ 249 : 백의 자리는 1~2, 십의 자리는 0 ~ 4, 1의 자리는 0~9  ==> ^[1-2]{1}[0-4]{1}[0-9]{1}$
250 ~ 255 : ^25[0-5]$


$num = 48; // 1 ~ 50 사이인지 검사
if(preg_match("/(^[1-9]{1}$|^[1-4]{1}[0-9]{1}$|^50$)/m",$num)){
    echo $num.'<br />';
} else {
    echo 'The number is out of range<br />';
}


728x90
블로그 이미지

Link2Me

,
728x90

정규표현식은 1970년대에 등장한 오래된 기술이다.

유닉스나 리눅스 시스템을 다루는 사람이라면 더더욱 잘 알아야 한다.

정규표현식을 처음에 접하면 너무 생소해서 어렵게만 느껴진다.

 

정규표현식을 제대로 다룰 줄 모르다보니 구글링 검색만 많이 하게 되는데 조금이라도 이해하고자 적어본다.

정규표현식은 텍스트에서 원하는 패턴을 찾는 도구다.

 

 ? : 0 또는 하나     {0,1} 와 같다.
 + : 1개 이상       {1,} 와 같다.
 * : 0 개 이상        {0,} 과 같다.

 [] : []안에 있는 문자열 중 한문자. 정규표현식에서 대괄호는 일반 문자가 아닌 메타문자로 인식한다.
 {} : {} 바로 앞에 있는 문자열(또는 문자)의 개수
 () : ()안에 있는 문자들의 그룹화. ( : 참조그룹 시작, ) : 참조그룹 끝.
  | : OR 연산자 기능



 w : 영문자, 숫자, _, 기타 스크립트 문자
 W : 영문자, 숫자, _, 기타 스크립트 문자를 제외한 문자

 s : 공백
 S : 공백을 제외한 모든 문자
 D : 숫자가 아닌 모든 문자
 d : 숫자
 i : 대소문자 무시
 정규식으로 한글의 범위는 \xa1-\xfe 로 표현
 ^ : 문자열의 시작 

 $ : 문자열의 마지막. 행의 끝.
 . : 문자열중 임의의 한문자(개행문자 제외)
a{2}b : aab 를 가진 문자열을 사용할 수 있다. 즉 (2) 는 {} 앞에 있는 문자 a 의 개수가 2개인 것을 의미
 
() : 찾는 패턴의 전체 또는 일부분을 괄호를 사용해서 그룹으로 묶으면 그 내용이 임시로 메모리에 저장된다.

 

사용할 수 있는 문자열을 지정하는 정규 표현식의 문자는 [] 이다.

[-.]? : 하이픈 또는 점이 0번 또는 1번 나온다는 의미다.

특정 문자열을 사용할 수 없도록 지정하고 싶다면, 지정하는 대괄호 [] 사이에 삿갓(^) 표시를 입력하면 된다.

[^123] 과 같이 사용하면 1,2,3 숫자는 문자열로 사용할 수 없다.

[] 안의 두 문자 사이에 하이픈(-)을 사용하게 되면 두 문자 사이의 범위(From - To)를 의미한다.

[0-9] : 0 ~ 9 까지의 숫자를 찾는다.

[5-9] : 5 ~ 9 사이의 숫자를 찾는다.

\d : 0 ~9 까지의 숫자중 하나

 

\D : 숫자가 아닌 문자를 모두 찾는다.

[^0-9] : 숫자가 아닌 문자를 모두 찾는다.

 

바로 앞 문자열의 반복을 의미하는 *,+,? 문자

.* : 임의의 문자를 0개 이상 찾아라.

정규 표현식의 Dot(.) 메타 문자는 줄바꿈 문자인 \n를 제외한 모든 문자와 매치됨을 의미한다.

 

[^\n]* 과 같이 사용하면 개행문자(\n)가 아닌 문자를 0개 이상 찾아라.

 

정규 표현식에서 특수문자를 사용하기 위한 역슬래시(\)

실제 사용해야 할 특수문자가 있을 때는 그 문자 앞에 역슬래시(\)로 해당 문자열을 이스케이프해야 한다.

 

^[_0-9a-zA-Z-] : ^ 는 문자열의 시작을 알리는 것이다.
처음 문자열 시작을 0 에서 9 까지의 숫자나 소문자 a 에서 소문자 z, 대문자 A 에서 대문자 Z 까지 사용

/^[a-z]+$/i : 대소문자 구분없이 알파벳으로 이루어진 문자열

 

\ : 이스케이프 문자. 여러 메타 문자들을 이스케이프하여 그대로 사용할 수 있게 한다.
    *, ?, +, [, { ,(, ), }, ], ^, $, |, \, . 등

 

 

$idx = "192.168.1.1가나다aacc";
$idx = preg_replace("/[^0-9\.]/", "", $idx); // 숫자와 컴마 이외 제거

 

 

$str = "https://www.abc.com/abc.php?mode=n&p=1&keyword='love'";
// $str 의 내용중 mode까지의 문자열 저장
$str = preg_replace('/(mode)(.*)/',"$1",$str);
echo $str.'<br/>';

$str = '<th scope="col">에러코드</th>';
$str = preg_replace("/<\/?(td|tr|tbody)[^>]*>/i", "", $str);
// [^>]* 는 > 가 아닌 문자를 0개 이상 찾아라.
echo $str.'<br/>';

 

preg_match($pattern, $str, $match);
$pattern : 정규식 패턴, $str : 추출할 문장, $match : 추출된 값을 배열에 저장

preg_match_all("패턴", "추출할 문장", "결과 배열");

 

preg_match - 첫번째 매치가 일어나면 실행을 중지한다. (즉, 최대 매치횟수는 1회)
preg_match_all - 전체 매치된 횟수를 반환하며, 오류시 FALSE를 반환한다.

 

<?php

$str = "부산광역시 연제구 (연산 1동) 158-77";
//preg_match("/\(\S+\)/",$str,$matches);
//preg_match("/\([^\s]+\)/",$str,$matches); // \S 는 [^\s] 와 같다.
preg_match("/\(.*\)/",$str,$matches); // 괄호 시작과 종료안에서 .* 임의의 문자를 0개 이상 찾는다.

echo $matches[0]."<br />";
echo str_replace(array('(',')'),"",$matches[0]).'<br />';

##########################################
// http://www.naver.com
// https? : http 또는 https
// /^(((http(s?))\:\/\/)?)([0-9a-zA-Z\-]+\.)+[a-zA-Z]{2,6}(\:[0-9]+)?(\/\S*)?$/

$mobileNO = "010-1234-7777";
$mobileNO = preg_replace("/\D/", "", $mobileNO); // 숫자가 아닌 모든 문자는 제거하라.

$mobileNO = preg_replace("/(^01[0|1|6|7|8|9]{1})([0-9]{3,4})([0-9]{4})$/", "\\1-\\2-\\3", $mobileNO);

echo $mobileNO.'<br />';

// [] : []안에 있는 문자열 중 한문자

// () : ()안에 있는 문자들의 그룹화

// {} : {} 바로 앞에 있는 문자열(또는 문자)의 개수

// ^01 : 시작을 01로 시작하고 0,1,6,7,8,9 중 1개의 글자를 그룹화하라.

// ([0-9]{3,4}) : 숫자 0~9 중 3개 또는 4개를 그룹화하라.

// ([0-9]{4}) : 숫자 0~9 중 4개를 그룹화하라.

 

 

이미지 다운로드시 상위 폴더로 이동하기 위한 ../ 정보가 포함되어 있는 걸 방지

$str ="../../image.png";
$str=preg_replace("/\.{2}\//","",$str);
echo $str.'<br/>';

 

$url ="http://www.naver.com/index.php";
preg_match("/^(https?:\/\/)?([^\/]+)/i",$url,$matches);
// ^ 시작이 http:// 또는 https:// 로 시작하는 문자열이 ? (0 또는 1개)

// ?는 바로 앞에 있는 괄호의 반복()을 의미한다.

// ? : 0개 또는 1개
// + : 1개 이상
// [^\/] : /가 아닐 때까지 +(1개 이상) 즉, /를 만날때까지의 값

echo '<pre>';print_r($matches);echo '</pre>';

 

공백이 2칸 이상일 때 1칸으로 변경

$str ="I'm a office    worker.";
$str=preg_replace("/\s{2,}/"," ",$str);
// 연속된 공백을 1개의 공백으로 변경

echo $str.'<br/>';

// \s{2,} : 공백이 2개 이상이면

 

$str ="주석이전 내용; // 주석 처리할 내용";
$str = preg_replace('/\/\/([^\n]+)/', "", $str); // (.*) 과 ([^\n]+) 는 같다.
// //부터 시작하여 개행문자까지 모두 공백으로 처리하라.
echo $str.'<br />';

 

$str ="<!--홍길동-->";
preg_match("/--([^--]+)/",$str,$matches);

// -- 부터 시작해서 --를 만날때까지의 값 추출

echo '<pre>';print_r($matches);echo '</pre>';

 

SQL 인젝션 공격 시도 방지

SQL Injection은 웹 어플리케이션에서 DB에 Query시 입력된 데이터의 유효성 검증을 하지 않아,
개발자가 의도하지 않는 동적 쿼리(Dynamic Query) 를 생성하여 DB정보를 열람하거나 조작할 수 있는 보안 취약점이다.

$userID = "admin";
$password = "password' OR 1='1";
$sql = "SELECT * FROM members WHERE userID='{$userID}' AND passwd='{$password}'";
echo $sql.'<br/>'; // 이걸 DB 에서 실행해보면 패스워드 무력화가 된다는 걸 알 수 있다.
$sql=preg_replace("/\-/","",$sql); // 주석 제거
$sql=preg_replace("/\s{1,}1\=(.*)+/","",$sql); // 공백이후 1=1이 있을 경우 제거
$sql=preg_replace("/\s{1,}(or|and|null|where|limit)/i"," ",$sql); // 공백이후 or, and 등이 있을 경우 제거
echo $sql.'<br/>';

 

여기서 한가지 더 테스트를 해봤다.

$userID = "admin";
$password = mysqli_real_escape_string($db,"password' OR 1='1 --");
$sql = "SELECT * FROM members WHERE userID='{$userID}' AND passwd='{$password}'";
echo $sql.'<br/>';

 

결과 :
SELECT * FROM members WHERE userID='admin' AND passwd='password\' OR 1=\'1 --'

 

' 앞에 역슬레쉬(\)를 붙여서 동작이 제대로 안되도록 하는 거라는 걸 확인할 수 있다.

 

$userID = mysqli_real_escape_string($db,"<script>documnet.cookie();</script>admin");

을 해보면 "admin"만 출력한다는 걸 확인할 수 있다.

 

패스워드나 아이디 입력한 걸

$password = "password' OR 1='1 --";

$password = preg_replace("/[\s\t\'\;\"\=\-]+/","", $password); // 공백이나 탭 제거, 특수문자 제거

으로 하면 공백 자체를 입력하지 못하게 하여 SQL Injection 공격을 방지할 수 있다.

 

정규식을 아이디/패스워드 입력용, 검색용 등 각각 별도로 함수를 만들어서 사용하는 게 좋을 것이다.

 

 

$str = "<script>documnet.cookie();</script>admin";
$str = preg_replace("/\<script[^\>]*\>(.*?)\<\/script\>/", "", $str); // 스크립트 제거
echo $str.'<br/>';

$str ="<!-- HTML -->주석";
$str = preg_replace("/\<\!\-{2}[^\>](.*?)\-{2}\>/", "", $str); // HTML 주석 제거
echo $str.'<br/>';

 

?>

 

플래그(flags)

 

정규 표현식 리터럴을 작성할 때 플래그를 사용하여 기본 검색 설정을 변경할 수 있다.

플래그(flag)

설명
i 검색 패턴을 비교할 때 대소문자를 구분하지 않도록 설정함.
g 검색 패턴을 비교할 때 일치하는 모든 부분을 선택하도록 설정함.
m Multi line을 표현하며 대상 문자열이 다중 라인의 문자열인 경우에도 검색하는 것을 의미한다.
y 대상 문자열의 현재 위치부터 비교를 시작하도록 설정함.
u 대상 문자열이 UTF-8로 인코딩된 것으로 설정함.

 

728x90
블로그 이미지

Link2Me

,
728x90

정규표현식을 제대로 사용할 수 있다면 대부분의 환경에서 어떤 데이터라도 떡 주무르듯이 다룰 수 있다.

(To master regular expressions is to master your data.)

 

정규표현식 : 문자열을 처리하는 방법 중의 하나로 특정한 조건의 문자를 검색하거나 치환하는 과정을 쉽게 처리할 수 있도록 하는 방법이다.

간단한 패턴부터 매우 복잡한 패턴에 이르기까지, 텍스트에서 패턴을 검색하고 찾아내는 것이 정규표현식의 핵심이다.

 

정규표현식과 관련있는 PHP 내장함수

preg_replace("패턴" , "바꿀 패턴" , "바꿀 문장");

 

preg_match("패턴","추출할 문장","결과 배열");

 

preg_match_all("패턴", "추출할 문장", "결과 배열");

 

preg_split("패턴", "추출할 문장");

 

preg_match - 첫번째 매치가 일어나면 실행을 중지한다. (즉, 최대 매치횟수는 1회)

pattern 에 주어진 정규표현식을 해당 문자열에서 찾는다.

패턴에 매치되면 1, 그렇지 않으면 0 을 반환한다. 1인 이유는 처음 매치 후에 검색을 중지하기 때문이다.

 

 

preg_match_all - 전체 매치된 횟수를 반환하며, 오류시 FALSE를 반환한다.

 

substr($원본문자열, $찾을위치, $길이)
 -  $원본문자열에서 $찾을위치의 인덱스(0 시작점)부터 $길이(개수) 만큼의 문자열을 잘라서 반환

 

정규식에서 사용하는 주요 기호
^ : 시작 (바로 뒤의 문자열로 시작되는 것을 의미)

$ : 마지막 글자 (앞의 문자열로 끝나는 것을 의미)

\d : 숫자

\D : 숫자가 아닌 경우, 즉 영문자, 공백, 구두점, 인용부호, 하이픈, 슬래시, 대괄호 등

\w : 영문자와 숫자, _

\W : 영문자와 숫자가 아닌 경우

\s : 공백문자

\S : 공백을 제외한 모든 문자. 즉 [^ \t\r\n] 또는 [^\s] 와 같다.

\t : 탭(tab)

\n : 개행문자

\r : 캐리지 리턴

| : OR 의 의미

\ : 특수문자 앞에서 특수문자 사용을 제외

[] : 문자 종류, 문자 범위 ← 메타문자

() : 문자를 그룹으로 묶음

 

{} : 반복횟수 ← 메타문자

* : 바로 앞의 문자가 최소 0회 이상 반복

+ : 바로 앞의 문자가 최소 1회 이상 반복

.  : 정확히 1개문자 매칭. 줄바꿈 문자를 제외한 모든 단일 문자.  \. 은 점(.)은 문자상수를 의미

? : 바로 앞의 문자가 0 또는 1개 문자 매칭

 

m{n} : m이 연속으로 n회 나오는 경우

m{n1, n2} : m이 n1 ~ n2회 나오는 경우

m{n,} : m 이 n회 이상 나오는 경우

 

5{3,5} : 숫자 5가 세번, 네번, 다섯 번 연속해서 등장한 경우를 찾는다. 

 

플래그(패턴 수식자)
g : 전역매칭
i : 대소문자 무시. 매칭시 알파벳의 대문자와 소문자를 구별하지 않는다.
m : 여러 줄 매칭. 줄 단위로 매칭을 진행한다.

u : 패턴 문자열을 UTF-8 인코딩으로 취급한다.

 

Perl 호환의 정규 표현식 함수는 문자 인코딩이 UTF-8 이면 u 수식자를 지정해서 정확하게 매칭할 수 있지만, UTF-8 이외의 문자는 정확하게 취급할 수 없다.

UTF-8 이외의 문자 인코딩이 정규 표현식에 매칭하려면 mb_ereg()함수 등의 멀티바이트에 대응하는 mbstring 정규 표현식 함수를 사용해야 한다.

처리하는 문자열의 인코딩이 UTF-8로 통일되어 있으면 Perl 호환의 정규 표현식 함수만 사용해도 문제가 없다.

 

[0-9] : 0부터 9까지의 숫자를 찾아라.

[^0-9] : 0부터 9까지의 숫자를 제외하고 찾아라. [^\d] 와 같은 의미다.

[01589] : 0,1,5,8,9 만 찾아라.
\d{3} : 숫자 3개를 찾아라.
-? : 하이픈(-)이 하나 이하 있다.
[.-] : 1개 또는 점(.) 또는 하이픈(-)을 찾아라

 

찾고자 하는 패턴의 전체 또는 일부분을 괄호를 사용해서 그룹으로 묶어 놓으면, 그  내용이 임시로 메모리에 저장된다. $1 또는 \1 은 첫 번째 참조 그룹을 의미하고 $2 또는 \2는 두번째 참조 그룹을 의미한다.

정규식에서 괄호()를 사용하면 순서대로 $1, $2, $3, ... 와 같이 불러서 사용 할 수 있다.
(^02.{0}|^01.{1}|[0-9]{3})
  - ^02.{0}   : ^는 정규식에서 시작을 의미하며 "02"로 시작 하는 경우를 말한다.
  -  "."은 문자 하나를 나타내는데 바로 뒤 괄호가 {0}이니 결과로는 "02"만 추출 한다는 내용
  - ^01.{1}   : 위와 마찬가지로 "01"로 시작하는 경우
  - .{1} 이므로 이후 1자리만 추출 즉 01X 로 시작하는 휴대폰을 의미

([0-9]{4}) : 바로 0-9까지의 숫자를 4자리 가져온다.

 

$str = preg_replace("/\s{2,}/", " ", $str); // s(공백문자)가 2회 이상 나오는 경우를 " " 로 변경

정규식을 만들 경우 원하는 결과가 나오는지 테스트해보고 싶다면

https://regexr.com/  또는

http://www.phpliveregex.com/p/6ik 에서 하면 된다.

 

http://www.slideshare.net/ 에서 검색어에 '정규식'을 입력하면 자바스크립트 정규식에 대한 좋은 자료가 나온다.

 

전화번호에 하이픈(-)을 넣어서 보기 좋게 정렬을 할 필요가 있을 경우 아래 함수를 이용하면 편하다.

 

<?php
// 전화번호의 숫자만 취한 후 중간에 하이픈(-)을 넣는다.
function add_hyphen($tel)
{
    $tel = preg_replace("/[^0-9]/", "", $tel);    // 숫자 이외 제거
    if (substr($tel,0,2)=='02')
        return preg_replace("/([0-9]{2})([0-9]{3,4})([0-9]{4})$/", "\\1-\\2-\\3", $tel);
    else if (strlen($tel)=='8' && (substr($tel,0,2)=='15' || substr($tel,0,2)=='16' || substr($tel,0,2)=='18'))
        // 지능망 번호이면
        return preg_replace("/([0-9]{4})([0-9]{4})$/", "\\1-\\2", $tel);
    else
        return preg_replace("/([0-9]{3})([0-9]{3,4})([0-9]{4})$/", "\\1-\\2-\\3", $tel);
}
?>

※ preg_replace 함수는 str_replace 함수보다 처리속도 상당히 늦다. 그러므로 꼭 preg_replace 함수를 써야 하는 경우에 쓰는 것이 좋다.

 

ereg*()함수를 사용하는 것은 보안상 위험하므로 PHP 5.3 이후부터 권장하지 않는다.

 

728x90
블로그 이미지

Link2Me

,