Ver3.0 ๐ฏ PHP ์ ๊ทํํ์๊ณผ PCRE ์์ ์ ๋ณต

๐ฏ PHP ์ ๊ทํํ์๊ณผ PCRE ์์ ์ ๋ณต
ํ ์คํธ ํจํด ๋งค์นญ์ ๋ชจ๋ ๊ฒ, ์น๊ตฌ์ฒ๋ผ ์ฝ๊ฒ ์๋ ค์ค๊ฒ!
๐ ์ ๊ทํํ์, ๋ ๋๊ตฌ๋?
์ผ, ํ๋ก๊ทธ๋๋ฐ ํ๋ค ๋ณด๋ฉด ํ
์คํธ ์ฒ๋ฆฌ๊ฐ ์ง์ง ๊ณจ์น ์ํ ๋ ๋ง์ง ์์? ๐ค
์ด๋ฉ์ผ ํ์ ์ฒดํฌํด์ผ ํ๋๋ฐ, ์ ํ๋ฒํธ ์ถ์ถํด์ผ ํ๋๋ฐ, URL ์ฐพ์์ผ ํ๋๋ฐ...
์ด๋ด ๋๋ง๋ค if๋ฌธ ์์ญ ๊ฐ ์ฐ๋ฉด์ "์ด๊ฒ ๋ง๋?" ์ถ์ ๋ ์์์.
๋ฐ๋ก ๊ทธ๋ ํ์ํ ๊ฒ ์ ๊ทํํ์(Regular Expression)์ด์ผ!
์์ด๋ก๋ Regex ๋๋ RegExp๋ผ๊ณ ๋ถ๋ฅด๋๋ฐ, ์ด๊ฑด ํ
์คํธ ํจํด์ ํํํ๋ ํน๋ณํ ๋ฌธ์์ด์ด์ผ.
๋ง์น ํ
์คํธ๋ฅผ ์ฐพ๋ ๋ง๋ฒ ์ฃผ๋ฌธ ๊ฐ์ ๊ฑฐ์ง. โจ
์ฝ๊ฒ ๋งํ๋ฉด "์ด๋ฐ ํจํด์ ํ ์คํธ๋ฅผ ์ฐพ์์ค!"๋ผ๊ณ ์ปดํจํฐ์๊ฒ ๋ช ๋ นํ๋ ๋ฐฉ๋ฒ์ด์ง.
์๋ฅผ ๋ค์ด "์ซ์ 3๊ฐ-์ซ์ 4๊ฐ-์ซ์ 4๊ฐ" ํจํด์ด๋ฉด ์ ํ๋ฒํธ๊ฒ ์ง?
์ด๊ฑธ ์ ๊ทํํ์์ผ๋ก ํํํ๋ฉด /\d{3}-\d{4}-\d{4}/ ์ด๋ ๊ฒ ๊ฐ๋จํด์ ธ!
๐ง PHP์ PCRE์ ๋ง๋จ
PHP์์ ์ ๊ทํํ์์ ์ธ ๋๋ PCRE(Perl Compatible Regular Expressions)๋ผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํด.
์ด๋ฆ์์ ์ ์ ์๋ฏ์ด Perl ์ธ์ด์ ์ ๊ทํํ์ ๋ฌธ๋ฒ๊ณผ ํธํ๋๋ ๋ฐฉ์์ด์ผ. ๐ช
PHP 4.2.0 ๋ฒ์ ๋ถํฐ ๊ธฐ๋ณธ์ผ๋ก ํ์ฌ๋์ด ์์ด์ ๋ณ๋ ์ค์น ์์ด ๋ฐ๋ก ์ธ ์ ์์ด.
PCRE๋ ๊ฐ๋ ฅํ๊ณ ์ ์ฐํด์ ๊ฑฐ์ ๋ชจ๋ ํ
์คํธ ํจํด ๋งค์นญ ์์
์ ์ฒ๋ฆฌํ ์ ์์ง!
- POSIX ์ ๊ทํํ์ (ereg ํจ์๊ตฐ) - PHP 5.3.0๋ถํฐ deprecated
- PCRE (preg ํจ์๊ตฐ) - ํ์ฌ ํ์ค
PCRE๊ฐ ๋ ๋น ๋ฅด๊ณ , ๊ธฐ๋ฅ๋ ๋ง๊ณ , ์ ๋์ฝ๋ ์ง์๋ ์ข์์ ์ง๊ธ์ PCRE๋ง ์ด๋ค๊ณ ๋ณด๋ฉด ๋ผ!
๐ PHP ์ ๊ทํํ์ ํต์ฌ ํจ์๋ค
PHP์์ PCRE๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด preg_๋ก ์์ํ๋ ํจ์๋ค์ ์จ์ผ ํด.
๊ฐ ํจ์๋ง๋ค ์ญํ ์ด ๋ค๋ฅด๋๊น ํ๋์ฉ ์์๋ณด์! ๐ฏ
1. preg_match() - ํจํด ์ฐพ๊ธฐ์ ๊ธฐ๋ณธ
๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ํจ์์ผ. ๋ฌธ์์ด์์ ํจํด์ด ํ ๋ฒ์ด๋ผ๋ ๋ํ๋๋์ง ํ์ธํด.
์ฐพ์ผ๋ฉด 1์ ๋ฐํํ๊ณ , ๋ชป ์ฐพ์ผ๋ฉด 0์ ๋ฐํํ์ง.
<?php
// ์ด๋ฉ์ผ ํ์ ์ฒดํฌ
$email = "user@example.com";
$pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
if (preg_match($pattern, $email)) {
echo "์ฌ๋ฐ๋ฅธ ์ด๋ฉ์ผ ํ์์
๋๋ค!";
} else {
echo "์ด๋ฉ์ผ ํ์์ด ์๋ชป๋์์ต๋๋ค.";
}
// ๋งค์นญ๋ ๊ฒฐ๊ณผ๋ฅผ ๋ฐฐ์ด๋ก ๋ฐ๊ธฐ
$text = "์ ์ ํ๋ฒํธ๋ 010-1234-5678์
๋๋ค.";
$pattern = '/\d{3}-\d{4}-\d{4}/';
if (preg_match($pattern, $text, $matches)) {
echo "์ฐพ์ ์ ํ๋ฒํธ: " . $matches[0]; // 010-1234-5678
}
?>
2. preg_match_all() - ๋ชจ๋ ๋งค์นญ ์ฐพ๊ธฐ
preg_match()๋ ์ฒซ ๋ฒ์งธ ๋งค์นญ๋ง ์ฐพ์ง๋ง,
preg_match_all()์ ๋ชจ๋ ๋งค์นญ์ ๋ค ์ฐพ์์ค. ๐
<?php
$text = "์ฐ๋ฝ์ฒ: 010-1111-2222, 02-3333-4444, 031-5555-6666";
$pattern = '/\d{2,3}-\d{3,4}-\d{4}/';
preg_match_all($pattern, $text, $matches);
echo "์ฐพ์ ์ ํ๋ฒํธ ๊ฐ์: " . count($matches[0]) . "\n";
foreach ($matches[0] as $phone) {
echo $phone . "\n";
}
// ์ถ๋ ฅ:
// ์ฐพ์ ์ ํ๋ฒํธ ๊ฐ์: 3
// 010-1111-2222
// 02-3333-4444
// 031-5555-6666
?>
3. preg_replace() - ํจํด ์นํํ๊ธฐ
์ฐพ์ ํจํด์ ๋ค๋ฅธ ๋ฌธ์์ด๋ก ๋ฐ๊ฟ์ฃผ๋ ํจ์์ผ.
ํ
์คํธ ์ ์ ๋ ํฌ๋งท ๋ณ๊ฒฝํ ๋ ์์ฒญ ์ ์ฉํด! โ๏ธ
<?php
// ์ ํ๋ฒํธ์์ ํ์ดํ ์ ๊ฑฐ
$phone = "010-1234-5678";
$clean_phone = preg_replace('/-/', '', $phone);
echo $clean_phone; // 01012345678
// HTML ํ๊ทธ ์ ๊ฑฐ
$html = "<p>์๋
ํ์ธ์</p><script>alert('xss')</script>";
$clean_text = preg_replace('/<[^>]+>/', '', $html);
echo $clean_text; // ์๋
ํ์ธ์alert('xss')
// ์ฌ๋ฌ ๊ณต๋ฐฑ์ ํ๋๋ก
$text = "์๋
ํ์ธ์ ๋ฐ๊ฐ์ต๋๋ค";
$clean = preg_replace('/\s+/', ' ', $text);
echo $clean; // ์๋
ํ์ธ์ ๋ฐ๊ฐ์ต๋๋ค
?>
4. preg_split() - ํจํด์ผ๋ก ๋ฌธ์์ด ๋๋๊ธฐ
explode()์ ๊ฐ๋ ฅํ ๋ฒ์ ์ด๋ผ๊ณ ๋ณด๋ฉด ๋ผ.
๋ณต์กํ ๊ตฌ๋ถ์๋ก๋ ๋ฌธ์์ด์ ๋๋ ์ ์์ด!
<?php
// ์ผํ๋ ์ธ๋ฏธ์ฝ๋ก ์ผ๋ก ๋๋๊ธฐ
$text = "์ฌ๊ณผ,๋ฐ๋๋;ํฌ๋,๋ธ๊ธฐ;์๋ฐ";
$fruits = preg_split('/[,;]/', $text);
print_r($fruits);
// Array ( [0] => ์ฌ๊ณผ [1] => ๋ฐ๋๋ [2] => ํฌ๋ [3] => ๋ธ๊ธฐ [4] => ์๋ฐ )
// ๊ณต๋ฐฑ ๋ฌธ์(์คํ์ด์ค, ํญ, ์ค๋ฐ๊ฟ)๋ก ๋๋๊ธฐ
$text = "PHP JavaScript\tPython\nJava";
$languages = preg_split('/\s+/', $text);
print_r($languages);
?>
5. preg_grep() - ๋ฐฐ์ด์์ ํจํด ๋งค์นญ ํํฐ๋ง
๋ฐฐ์ด์ ์์ ์ค์์ ํจํด๊ณผ ๋งค์นญ๋๋ ๊ฒ๋ง ๊ณจ๋ผ๋ด๋ ํจ์์ผ.
๋ฐ์ดํฐ ํํฐ๋งํ ๋ ์ ๋ง ํธํด! ๐ฃ
<?php
$emails = [
"user@example.com",
"invalid-email",
"admin@test.co.kr",
"wrong@",
"contact@company.net"
];
$pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
$valid_emails = preg_grep($pattern, $emails);
print_r($valid_emails);
// Array ( [0] => user@example.com [2] => admin@test.co.kr [4] => contact@company.net )
?>
๐จ ์ ๊ทํํ์ ํจํด ๋ฌธ๋ฒ ์์ ์ ๋ณต
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์ ๊ทํํ์ ํจํด์ ์ด๋ป๊ฒ ์ฐ๋์ง ์์๋ณด์!
์ฒ์์ ์ธ๊ณ์ด ๊ฐ์ง๋ง ์ต์ํด์ง๋ฉด ์ง์ง ๊ฐ๋ ฅํ ๋๊ตฌ๊ฐ ๋ผ. ๐ช
๊ธฐ๋ณธ ๋ฉํ๋ฌธ์๋ค
| ๋ฉํ๋ฌธ์ | ์๋ฏธ | ์์ |
|---|---|---|
| . | ์ค๋ฐ๊ฟ์ ์ ์ธํ ๋ชจ๋ ๋ฌธ์ ํ๋ | /a.c/ โ abc, aXc, a9c ๋งค์นญ |
| ^ | ๋ฌธ์์ด์ ์์ | /^Hello/ โ Hello๋ก ์์ |
| $ | ๋ฌธ์์ด์ ๋ | /world$/ โ world๋ก ๋๋จ |
| * | 0๋ฒ ์ด์ ๋ฐ๋ณต | /ab*c/ โ ac, abc, abbc ๋งค์นญ |
| + | 1๋ฒ ์ด์ ๋ฐ๋ณต | /ab+c/ โ abc, abbc (ac๋ ์๋จ) |
| ? | 0๋ฒ ๋๋ 1๋ฒ | /colou?r/ โ color, colour |
| | | OR ์กฐ๊ฑด | /cat|dog/ โ cat ๋๋ dog |
| () | ๊ทธ๋ฃนํ | /(ab)+/ โ ab, abab, ababab |
| [] | ๋ฌธ์ ํด๋์ค | /[abc]/ โ a, b, c ์ค ํ๋ |
| \ | ์ด์ค์ผ์ดํ ๋ฌธ์ | /\./ โ ๋ง์นจํ ์์ฒด๋ฅผ ์ฐพ์ |
์๋์(Quantifiers) ์์ธ
{n,} - n๋ฒ ์ด์
{n,m} - n๋ฒ ์ด์ m๋ฒ ์ดํ
์์:
/\d{3}/ โ ์ซ์ ์ ํํ 3๊ฐ
/\d{3,}/ โ ์ซ์ 3๊ฐ ์ด์
/\d{3,5}/ โ ์ซ์ 3~5๊ฐ
<?php
// ์ ํ๋ฒํธ ํจํด (์ง์ญ๋ฒํธ 2-3์๋ฆฌ, ๊ตญ๋ฒ 3-4์๋ฆฌ, ๋ฒํธ 4์๋ฆฌ)
$pattern = '/\d{2,3}-\d{3,4}-\d{4}/';
// ๋น๋ฐ๋ฒํธ ๊ฒ์ฆ (8~16์, ์๋ฌธ+์ซ์ ํ์)
$password_pattern = '/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,16}$/';
// ์ฐํธ๋ฒํธ (5์๋ฆฌ ์ซ์)
$zipcode_pattern = '/^\d{5}$/';
?>
๋ฌธ์ ํด๋์ค์ ๋จ์ถ ํํ
| ๋จ์ถ ํํ | ์๋ฏธ | ๋์ผ ํํ |
|---|---|---|
| \d | ์ซ์ | [0-9] |
| \D | ์ซ์๊ฐ ์๋ ๊ฒ | [^0-9] |
| \w | ๋จ์ด ๋ฌธ์ | [a-zA-Z0-9_] |
| \W | ๋จ์ด ๋ฌธ์๊ฐ ์๋ ๊ฒ | [^a-zA-Z0-9_] |
| \s | ๊ณต๋ฐฑ ๋ฌธ์ | ์คํ์ด์ค, ํญ, ์ค๋ฐ๊ฟ ๋ฑ |
| \S | ๊ณต๋ฐฑ์ด ์๋ ๋ฌธ์ | - |
| \b | ๋จ์ด ๊ฒฝ๊ณ | ๋จ์ด์ ์์์ด๋ ๋ |
| \B | ๋จ์ด ๊ฒฝ๊ณ๊ฐ ์๋ | - |
<?php
// ๋จ์ด ๊ฒฝ๊ณ ํ์ฉ ์์
$text = "cat cats category";
// 'cat'์ด๋ผ๋ ๋จ์ด๋ง ์ ํํ ์ฐพ๊ธฐ
preg_match_all('/\bcat\b/', $text, $matches);
print_r($matches[0]); // Array ( [0] => cat )
// 'cat'์ผ๋ก ์์ํ๋ ๋ชจ๋ ๋จ์ด
preg_match_all('/\bcat\w*/', $text, $matches);
print_r($matches[0]); // Array ( [0] => cat [1] => cats [2] => category )
?>
๐ฏ ์ค์ ํจํด ์์ ๋ชจ์
์ด๋ก ๋ง ์๋ฉด ๋ญํด, ์ค์ ์์ ๋ชป ์ฐ๋ฉด! ๐
์์ฃผ ์ฐ์ด๋ ํจํด๋ค์ ๋ชจ์๋ดค์ด. ๋ณต์ฌํด์ ๋ฐ๋ก ์ธ ์ ์๊ฒ ์ฃผ์๋ ๋ฌ์๋์ผ๋๊น ์ฐธ๊ณ ํด!
๐ง ์ด๋ฉ์ผ ๊ฒ์ฆ
<?php
// ๊ธฐ๋ณธ ์ด๋ฉ์ผ ํจํด
$pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
// ๋ ์๊ฒฉํ ์ด๋ฉ์ผ ํจํด (RFC 5322 ๊ธฐ๋ฐ)
$strict_pattern = '/^(?!.*\.\.)(?!.*\.$)[a-zA-Z0-9._%+-]{1,64}@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
function validateEmail($email) {
$pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
return preg_match($pattern, $email) === 1;
}
// ํ
์คํธ
echo validateEmail("user@example.com") ? "์ ํจ" : "๋ฌดํจ"; // ์ ํจ
echo validateEmail("invalid@") ? "์ ํจ" : "๋ฌดํจ"; // ๋ฌดํจ
?>
๐ฑ ์ ํ๋ฒํธ ๊ฒ์ฆ
<?php
// ํ๊ตญ ํด๋ํฐ ๋ฒํธ (010-1234-5678)
$mobile_pattern = '/^01[0-9]-\d{3,4}-\d{4}$/';
// ํ์ดํ ์๊ฑฐ๋ ์๊ฑฐ๋ ๋ ๋ค ํ์ฉ
$flexible_pattern = '/^01[0-9]-?\d{3,4}-?\d{4}$/';
// ์ผ๋ฐ ์ ํ๋ฒํธ (02-123-4567, 031-1234-5678)
$phone_pattern = '/^0\d{1,2}-\d{3,4}-\d{4}$/';
function formatPhone($phone) {
// ์ซ์๋ง ์ถ์ถ
$numbers = preg_replace('/[^0-9]/', '', $phone);
// ํด๋ํฐ ๋ฒํธ ํ์์ผ๋ก ๋ณํ
if (preg_match('/^(01[0-9])(\d{3,4})(\d{4})$/', $numbers, $matches)) {
return $matches[1] . '-' . $matches[2] . '-' . $matches[3];
}
return $phone;
}
echo formatPhone("01012345678"); // 010-1234-5678
?>
๐ ๋น๋ฐ๋ฒํธ ๊ฐ๋ ๊ฒ์ฆ
<?php
// ์ต์ 8์, ์๋ฌธ ๋์๋ฌธ์, ์ซ์, ํน์๋ฌธ์ ๊ฐ 1๊ฐ ์ด์
$strong_password = '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/';
// ์ต์ 8์, ์๋ฌธ+์ซ์ ์กฐํฉ
$medium_password = '/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/';
function checkPasswordStrength($password) {
$patterns = [
'weak' => '/^.{6,}$/', // 6์ ์ด์
'medium' => '/^(?=.*[A-Za-z])(?=.*\d).{8,}$/', // 8์ ์ด์, ์๋ฌธ+์ซ์
'strong' => '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).{8,}$/' // ๊ฐ๋ ฅ
];
if (preg_match($patterns['strong'], $password)) {
return '๊ฐ๋ ฅ';
} elseif (preg_match($patterns['medium'], $password)) {
return '๋ณดํต';
} elseif (preg_match($patterns['weak'], $password)) {
return '์ฝํจ';
}
return '๋งค์ฐ ์ฝํจ';
}
echo checkPasswordStrength("Pass123!"); // ๊ฐ๋ ฅ
echo checkPasswordStrength("password123"); // ๋ณดํต
?>
๐ URL ๊ฒ์ฆ ๋ฐ ์ถ์ถ
<?php
// ๊ธฐ๋ณธ URL ํจํด
$url_pattern = '/^https?:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/';
// ํ
์คํธ์์ URL ์ถ์ถ
$text = "๋ฐฉ๋ฌธํ์ธ์: https://www.example.com ๊ทธ๋ฆฌ๊ณ http://test.co.kr/page";
preg_match_all('/https?:\/\/[^\s]+/', $text, $urls);
print_r($urls[0]);
// Array ( [0] => https://www.example.com [1] => http://test.co.kr/page )
// URL์์ ๋๋ฉ์ธ๋ง ์ถ์ถ
function extractDomain($url) {
if (preg_match('/^https?:\/\/([^\/]+)/', $url, $matches)) {
return $matches[1];
}
return null;
}
echo extractDomain("https://www.example.com/page"); // www.example.com
?>
๐ณ ์ ์ฉ์นด๋ ๋ฒํธ ๊ฒ์ฆ
<?php
// ์ ์ฉ์นด๋ ๋ฒํธ (4์๋ฆฌ-4์๋ฆฌ-4์๋ฆฌ-4์๋ฆฌ)
$card_pattern = '/^\d{4}-\d{4}-\d{4}-\d{4}$/';
// ํ์ดํ ์์ด๋ ํ์ฉ
$card_flexible = '/^\d{4}-?\d{4}-?\d{4}-?\d{4}$/';
function maskCardNumber($card) {
// ๋ง์ง๋ง 4์๋ฆฌ๋ง ๋ณด์ด๊ฒ
return preg_replace('/^(\d{4})-?(\d{4})-?(\d{4})-?(\d{4})$/', '****-****-****-$4', $card);
}
echo maskCardNumber("1234-5678-9012-3456"); // ****-****-****-3456
echo maskCardNumber("1234567890123456"); // ****-****-****-3456
?>
๐ ๋ ์ง ํ์ ๊ฒ์ฆ
<?php
// YYYY-MM-DD ํ์
$date_pattern = '/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/';
// YYYY.MM.DD ๋๋ YYYY/MM/DD
$date_flexible = '/^\d{4}[.\/-](0[1-9]|1[0-2])[.\/-](0[1-9]|[12]\d|3[01])$/';
function convertDateFormat($date) {
// ๋ค์ํ ํ์์ YYYY-MM-DD๋ก ํต์ผ
if (preg_match('/^(\d{4})[.\/-](\d{1,2})[.\/-](\d{1,2})$/', $date, $matches)) {
return sprintf('%04d-%02d-%02d', $matches[1], $matches[2], $matches[3]);
}
return $date;
}
echo convertDateFormat("2024.3.5"); // 2024-03-05
echo convertDateFormat("2024/12/25"); // 2024-12-25
?>
๐ ์ฃผ์ ๋ฐ ์ฐํธ๋ฒํธ
<?php
// ํ๊ตญ ์ฐํธ๋ฒํธ (5์๋ฆฌ)
$zipcode_pattern = '/^\d{5}$/';
// ๊ตฌ ์ฐํธ๋ฒํธ (123-456) ํ์๋ ํ์ฉ
$zipcode_old = '/^\d{3}-?\d{3}$/';
// ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ (์์๋ฆฌ๋ง, ๋ท์๋ฆฌ ๋ง์คํน)
$jumin_pattern = '/^(\d{6})-?([1-4]\d{6})$/';
function maskJumin($jumin) {
return preg_replace('/^(\d{6})-?(\d{7})$/', '$1-*******', $jumin);
}
echo maskJumin("900101-1234567"); // 900101-*******
?>
๐ ๊ณ ๊ธ ๊ธฐ๋ฅ: ๊ทธ๋ฃน๊ณผ ์บก์ฒ
์ ๊ทํํ์์ ์ง์ง ๊ฐ๋ ฅํจ์ ๊ทธ๋ฃนํ์ ์บก์ฒ์ ์์ด!
ํจํด์ ์ผ๋ถ๋ฅผ ๊ทธ๋ฃน์ผ๋ก ๋ฌถ์ด์ ๋์ค์ ์ฌ์ฌ์ฉํ๊ฑฐ๋ ์ถ์ถํ ์ ์๊ฑฐ๋ . ๐
์บก์ฒ ๊ทธ๋ฃน (Capturing Groups)
๊ดํธ ()๋ก ๋ฌถ์ผ๋ฉด ๊ทธ ๋ถ๋ถ์ด ๋ณ๋๋ก ์บก์ฒ๋ผ์ ๋ฐฐ์ด์ ์ ์ฅ๋ผ.
<?php
$text = "์ ์ด๋ฉ์ผ์ john.doe@example.com์
๋๋ค.";
$pattern = '/([a-zA-Z0-9._%+-]+)@([a-zA-Z0-9.-]+)\.([a-zA-Z]{2,})/';
if (preg_match($pattern, $text, $matches)) {
echo "์ ์ฒด ๋งค์นญ: " . $matches[0] . "\n"; // john.doe@example.com
echo "์ฌ์ฉ์๋ช
: " . $matches[1] . "\n"; // john.doe
echo "๋๋ฉ์ธ: " . $matches[2] . "\n"; // example
echo "์ต์์ ๋๋ฉ์ธ: " . $matches[3] . "\n"; // com
}
// ์ด๋ฆ ๋ถ๋ฆฌํ๊ธฐ
$name = "ํ๊ธธ๋";
$pattern = '/^([๊ฐ-ํฃ])([๊ฐ-ํฃ]+)$/';
if (preg_match($pattern, $name, $matches)) {
echo "์ฑ: " . $matches[1] . "\n"; // ํ
echo "์ด๋ฆ: " . $matches[2] . "\n"; // ๊ธธ๋
}
?>
๋ช ๋ช ๋ ์บก์ฒ ๊ทธ๋ฃน (Named Capturing Groups)
์ซ์ ์ธ๋ฑ์ค ๋์ ์ด๋ฆ์ผ๋ก ์ ๊ทผํ ์ ์์ด์ ์ฝ๋๊ฐ ํจ์ฌ ์ฝ๊ธฐ ์ฌ์์ ธ!
(?P<name>pattern) ํ์์ผ๋ก ์ฌ์ฉํด.
<?php
$text = "์๋
์์ผ: 1990-05-15";
$pattern = '/(?P<year>\d{4})-(?P<month>\d{2})-(?P<day>\d{2})/';
if (preg_match($pattern, $text, $matches)) {
echo "๋
: " . $matches['year'] . "\n"; // 1990
echo "์: " . $matches['month'] . "\n"; // 05
echo "์ผ: " . $matches['day'] . "\n"; // 15
}
// URL ํ์ฑ
$url = "https://www.example.com:8080/path/to/page?id=123";
$pattern = '/^(?P<protocol>https?):\/\/(?P<domain>[^:\/]+)(:(?P<port>\d+))?(?P<path>\/[^?]*)?(\?(?P<query>.*))?$/';
if (preg_match($pattern, $url, $matches)) {
echo "ํ๋กํ ์ฝ: " . $matches['protocol'] . "\n"; // https
echo "๋๋ฉ์ธ: " . $matches['domain'] . "\n"; // www.example.com
echo "ํฌํธ: " . ($matches['port'] ?? '๊ธฐ๋ณธ') . "\n"; // 8080
echo "๊ฒฝ๋ก: " . ($matches['path'] ?? '/') . "\n"; // /path/to/page
echo "์ฟผ๋ฆฌ: " . ($matches['query'] ?? '์์') . "\n"; // id=123
}
?>
๋น์บก์ฒ ๊ทธ๋ฃน (Non-Capturing Groups)
๊ทธ๋ฃนํ๋ ํ๊ณ ์ถ์๋ฐ ์บก์ฒ๋ ์ ํ๊ณ ์ถ์ ๋ ์ฌ์ฉํด.
(?:pattern) ํ์์ด์ผ. ์ฑ๋ฅ๋ ์ฝ๊ฐ ๋ ์ข์!
<?php
// ์บก์ฒ ๊ทธ๋ฃน ์ฌ์ฉ (๋ถํ์ํ ์บก์ฒ ๋ฐ์)
$pattern1 = '/(http|https):\/\/([a-z.]+)/';
// ๋น์บก์ฒ ๊ทธ๋ฃน ์ฌ์ฉ (ํ์ํ ๊ฒ๋ง ์บก์ฒ)
$pattern2 = '/(?:http|https):\/\/([a-z.]+)/';
$url = "https://example.com";
preg_match($pattern1, $url, $matches1);
print_r($matches1);
// Array ( [0] => https://example.com [1] => https [2] => example.com )
preg_match($pattern2, $url, $matches2);
print_r($matches2);
// Array ( [0] => https://example.com [1] => example.com )
// [1]์ด http/https๊ฐ ์๋๋ผ ๋๋ฉ์ธ์ด ๋จ!
?>
์ญ์ฐธ์กฐ (Backreferences)
์์์ ์บก์ฒํ ๊ทธ๋ฃน์ ํจํด ์์์ ๋ค์ ์ฐธ์กฐํ ์ ์์ด.
\1, \2 ๊ฐ์ ํ์์ผ๋ก ์ฌ์ฉํ์ง.
<?php
// ๋ฐ๋ณต๋๋ ๋จ์ด ์ฐพ๊ธฐ
$text = "์ด๊ฒ์ ์ด๊ฒ์ ์ค๋ณต๋ ๋จ์ด์
๋๋ค.";
$pattern = '/(\b\w+\b)\s+\1/u';
if (preg_match($pattern, $text, $matches)) {
echo "์ค๋ณต ๋จ์ด: " . $matches[1]; // ์ด๊ฒ์
}
// HTML ํ๊ทธ ์ ๋งค์นญ
$html = "<div>๋ด์ฉ</div>";
$pattern = '/<(\w+)>.*?<\/\1>/';
if (preg_match($pattern, $html)) {
echo "์ฌ๋ฐ๋ฅธ ํ๊ทธ ์์
๋๋ค.";
}
// ๊ฐ์ ๋ฐ์ดํ๋ก ๋ฌถ์ธ ๋ฌธ์์ด ์ฐพ๊ธฐ
$text = 'He said "Hello" and she said \'Hi\'';
$pattern = '/(["\']).*?\1/';
preg_match_all($pattern, $text, $matches);
print_r($matches[0]);
// Array ( [0] => "Hello" [1] => 'Hi' )
?>
โ๏ธ ์ ๊ทํํ์ ํ๋๊ทธ(Modifiers)
ํจํด ๋ค์ ๋ถ์ด๋ ํ๋๊ทธ๋ก ๋งค์นญ ๋์์ ์กฐ์ ํ ์ ์์ด.
PHP PCRE์์ ์์ฃผ ์ฐ๋ ํ๋๊ทธ๋ค์ ์์๋ณด์! ๐๏ธ
| ํ๋๊ทธ | ์ด๋ฆ | ์ค๋ช |
|---|---|---|
| i | PCRE_CASELESS | ๋์๋ฌธ์ ๊ตฌ๋ถ ์ ํจ |
| m | PCRE_MULTILINE | ^์ $๊ฐ ๊ฐ ์ค์ ์์/๋์ ๋งค์นญ |
| s | PCRE_DOTALL | .(์ )์ด ์ค๋ฐ๊ฟ ๋ฌธ์๋ ๋งค์นญ |
| x | PCRE_EXTENDED | ํจํด ๋ด ๊ณต๋ฐฑ๊ณผ ์ฃผ์ ๋ฌด์ |
| u | PCRE_UTF8 | UTF-8๋ก ์ฒ๋ฆฌ (ํ๊ธ ๋ฑ) |
| U | PCRE_UNGREEDY | ์๋์๋ฅผ non-greedy๋ก ๋ณ๊ฒฝ |
| A | PCRE_ANCHORED | ๋ฌธ์์ด ์์์์๋ง ๋งค์นญ |
| D | PCRE_DOLLAR_ENDONLY | $๊ฐ ๋ฌธ์์ด ๋์๋ง ๋งค์นญ |
ํ๋๊ทธ ์ฌ์ฉ ์์
<?php
// i ํ๋๊ทธ: ๋์๋ฌธ์ ๋ฌด์
$text = "Hello World";
echo preg_match('/hello/i', $text) ? "๋งค์นญ" : "๋ถ์ผ์น"; // ๋งค์นญ
// m ํ๋๊ทธ: ๋ฉํฐ๋ผ์ธ ๋ชจ๋
$text = "์ฒซ ๋ฒ์งธ ์ค\n๋ ๋ฒ์งธ ์ค\n์ธ ๋ฒ์งธ ์ค";
preg_match_all('/^.+$/m', $text, $matches);
print_r($matches[0]);
// Array ( [0] => ์ฒซ ๋ฒ์งธ ์ค [1] => ๋ ๋ฒ์งธ ์ค [2] => ์ธ ๋ฒ์งธ ์ค )
// s ํ๋๊ทธ: ์ ์ด ์ค๋ฐ๊ฟ๋ ๋งค์นญ
$text = "์ฒซ ์ค\n๋์งธ ์ค";
echo preg_match('/์ฒซ ์ค.๋์งธ ์ค/s', $text) ? "๋งค์นญ" : "๋ถ์ผ์น"; // ๋งค์นญ
// u ํ๋๊ทธ: UTF-8 ์ฒ๋ฆฌ (ํ๊ธ ์ฌ์ฉ ์ ํ์!)
$text = "์๋
ํ์ธ์";
preg_match_all('/./u', $text, $matches);
echo count($matches[0]); // 5 (u ์์ผ๋ฉด ๋ฐ์ดํธ ๋จ์๋ก ๊ณ์ฐ๋จ)
// x ํ๋๊ทธ: ๊ฐ๋
์ฑ ์ข์ ํจํด ์์ฑ
$pattern = '/
^ # ๋ฌธ์์ด ์์
(?P<year>\d{4}) # ๋
๋ 4์๋ฆฌ
- # ํ์ดํ
(?P<month>\d{2}) # ์ 2์๋ฆฌ
- # ํ์ดํ
(?P<day>\d{2}) # ์ผ 2์๋ฆฌ
$ # ๋ฌธ์์ด ๋
/x';
preg_match($pattern, "2024-03-15", $matches);
print_r($matches);
// U ํ๋๊ทธ: non-greedy ๊ธฐ๋ณธ๊ฐ
$html = "<div>์ฒซ ๋ฒ์งธ</div><div>๋ ๋ฒ์งธ</div>";
preg_match_all('/<div>.*<\/div>/U', $html, $matches);
print_r($matches[0]);
// Array ( [0] => <div>์ฒซ ๋ฒ์งธ</div> [1] => <div>๋ ๋ฒ์งธ</div> )
?>
์ ๊ทธ๋ฌ๋ฉด ๋ฌธ์๊ฐ ๊นจ์ง๊ฑฐ๋ ์์๊ณผ ๋ค๋ฅธ ๊ฒฐ๊ณผ๊ฐ ๋์ฌ ์ ์์ด์.
์: /[๊ฐ-ํฃ]+/u โ ์ด๋ ๊ฒ!
๐ช Lookahead์ Lookbehind (์ ๋ฐฉํ์/ํ๋ฐฉํ์)
์ด๊ฑด ์ข ๊ณ ๊ธ ๊ธฐ๋ฅ์ธ๋ฐ, ์์๋๋ฉด ์์ฒญ ์ ์ฉํด!
ํน์ ํจํด์ ์์ด๋ ๋ค๋ฅผ ํ์ธํ๋, ์ค์ ๋ก ๋งค์นญ์๋ ํฌํจ์ํค์ง ์๋ ๊ฑฐ์ผ. ๐ญ
Positive Lookahead (?=...)
"์ด ํจํด ๋ค์ ํน์ ํจํด์ด ์์ด์ผ ํด" ๋ผ๋ ์กฐ๊ฑด์ด์ผ.
<?php
// ์ซ์ ๋ค์ '์'์ด ์๋ ์ซ์๋ง ์ฐพ๊ธฐ
$text = "๊ฐ๊ฒฉ์ 10000์์ด๊ณ , ์๋์ 5๊ฐ์
๋๋ค.";
preg_match_all('/\d+(?=์)/', $text, $matches);
print_r($matches[0]); // Array ( [0] => 10000 )
// ๋น๋ฐ๋ฒํธ ๊ฒ์ฆ: ์ต์ 8์, ์ซ์ ํฌํจ ํ์
$password_pattern = '/^(?=.*\d).{8,}$/';
echo preg_match($password_pattern, "pass1234") ? "์ ํจ" : "๋ฌดํจ"; // ์ ํจ
// ์ฌ๋ฌ ์กฐ๊ฑด ๋์ ์ฒดํฌ
$strong_pass = '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).{8,}$/';
// ์๋ฌธ์, ๋๋ฌธ์, ์ซ์, ํน์๋ฌธ์ ๋ชจ๋ ํฌํจ
?>
Negative Lookahead (?!...)
"์ด ํจํด ๋ค์ ํน์ ํจํด์ด ์์ด์ผ ํด" ๋ผ๋ ์กฐ๊ฑด์ด์ผ.
<?php
// ์ซ์ ๋ค์ '์'์ด ์๋ ์ซ์๋ง ์ฐพ๊ธฐ
$text = "๊ฐ๊ฒฉ์ 10000์์ด๊ณ , ์๋์ 5๊ฐ์
๋๋ค.";
preg_match_all('/\d+(?!์)/', $text, $matches);
print_r($matches[0]); // Array ( [0] => 1000 [1] => 5 )
// 10000์ ๋ง์ง๋ง 0๊ณผ 5๊ฐ ๋งค์นญ๋จ
// ํน์ ๋จ์ด๋ฅผ ์ ์ธํ ๋จ์ด ์ฐพ๊ธฐ
$text = "apple banana orange apple grape";
preg_match_all('/\b(?!apple\b)\w+/', $text, $matches);
print_r($matches[0]); // Array ( [0] => banana [1] => orange [2] => grape )
?>
Positive Lookbehind (?<=...)
"์ด ํจํด ์์ ํน์ ํจํด์ด ์์ด์ผ ํด" ๋ผ๋ ์กฐ๊ฑด์ด์ผ.
<?php
// '$' ๊ธฐํธ ๋ค์ ์ซ์๋ง ์ฐพ๊ธฐ
$text = "๊ฐ๊ฒฉ: $100, ํ ์ธ: $20, ์๋: 5๊ฐ";
preg_match_all('/(?<=\$)\d+/', $text, $matches);
print_r($matches[0]); // Array ( [0] => 100 [1] => 20 )
// '@' ๋ค์ ๋๋ฉ์ธ๋ง ์ถ์ถ
$text = "์ฐ๋ฝ์ฒ: user@example.com, admin@test.co.kr";
preg_match_all('/(?<=@)[a-z0-9.-]+/', $text, $matches);
print_r($matches[0]); // Array ( [0] => example.com [1] => test.co.kr )
?>
Negative Lookbehind (?<!...)
"์ด ํจํด ์์ ํน์ ํจํด์ด ์์ด์ผ ํด" ๋ผ๋ ์กฐ๊ฑด์ด์ผ.
<?php
// '$' ๊ธฐํธ๊ฐ ์์ ์๋ ์ซ์๋ง ์ฐพ๊ธฐ
$text = "๊ฐ๊ฒฉ: $100, ์๋: 5๊ฐ";
preg_match_all('/(?<!\$)\b\d+\b/', $text, $matches);
print_r($matches[0]); // Array ( [0] => 5 )
// 'http://' ๋๋ 'https://'๋ก ์์ํ์ง ์๋ URL ์ฐพ๊ธฐ
$text = "example.com, https://secure.com, test.org";
preg_match_all('/(?<!https?:\/\/)\b[a-z]+\.com\b/', $text, $matches);
print_r($matches[0]); // Array ( [0] => example.com )
?>
์ฆ, *, + ๊ฐ์ ๊ฐ๋ณ ์๋์๋ ์ฌ์ฉ ๋ถ๊ฐ!
โ (?<=\d+) - ์ ๋จ
โ (?<=\d{3}) - ๋จ
๐ก๏ธ ๋ณด์๊ณผ ์ฑ๋ฅ ๊ณ ๋ ค์ฌํญ
์ ๊ทํํ์์ ๊ฐ๋ ฅํ์ง๋ง, ์๋ชป ์ฐ๋ฉด ๋ณด์ ๋ฌธ์ ๋ ์ฑ๋ฅ ์ ํ๊ฐ ๋ฐ์ํ ์ ์์ด.
์ค๋ฌด์์ ๊ผญ ์์์ผ ํ ์ฃผ์์ฌํญ๋ค์ ์ ๋ฆฌํด๋ดค์ด! โก
ReDoS (Regular Expression Denial of Service) ๊ณต๊ฒฉ
์
์์ ์ผ๋ก ์์ฑ๋ ์
๋ ฅ๊ฐ์ผ๋ก ์ ๊ทํํ์ ์ฒ๋ฆฌ ์๊ฐ์ ๊ธฐํ๊ธ์์ ์ผ๋ก ๋๋ ค์
์๋ฒ๋ฅผ ๋ง๋น์ํค๋ ๊ณต๊ฒฉ์ด์ผ. ํนํ ์ค์ฒฉ๋ ์๋์๊ฐ ์ํํด!
โ /(a|a)*$/
โ /(a|ab)*$/
์ด๋ฐ ํจํด๋ค์ ์ ๋ ฅ์ด ๊ธธ์ด์ง์๋ก ์ฒ๋ฆฌ ์๊ฐ์ด ํญ๋ฐ์ ์ผ๋ก ์ฆ๊ฐํด์!
<?php
// ๋์ ์: ReDoS ์ทจ์ฝ
$bad_pattern = '/(a+)+$/';
$input = str_repeat('a', 30) . 'b'; // aaaa...aaab
// ์ด ์
๋ ฅ์ ์์ฒญ๋ ์๊ฐ์ด ๊ฑธ๋ฆผ!
// ์ข์ ์: ์์ ํ ํจํด
$good_pattern = '/^a+$/';
// ๋๋
$good_pattern = '/^a{1,100}$/'; // ์ต๋ ๊ธธ์ด ์ ํ
// ํ์์์ ์ค์ ์ผ๋ก ๋ณดํธ
ini_set('pcre.backtrack_limit', '100000');
ini_set('pcre.recursion_limit', '100000');
function safeMatch($pattern, $subject, $timeout = 1) {
$start = microtime(true);
$result = @preg_match($pattern, $subject);
$elapsed = microtime(true) - $start;
if ($elapsed > $timeout) {
error_log("์ ๊ทํํ์ ์ฒ๋ฆฌ ์๊ฐ ์ด๊ณผ: {$elapsed}์ด");
return false;
}
return $result;
}
?>
์ ๋ ฅ๊ฐ ๊ฒ์ฆ๊ณผ ์ด์ค์ผ์ดํ
์ฌ์ฉ์ ์ ๋ ฅ์ ์ ๊ทํํ์์ ์ง์ ์ฌ์ฉํ ๋๋ ๋ฐ๋์ ์ด์ค์ผ์ดํ ์ฒ๋ฆฌ๋ฅผ ํด์ผ ํด!
<?php
// ์ฌ์ฉ์ ์
๋ ฅ์ ํจํด์ ์์ ํ๊ฒ ์ฌ์ฉํ๊ธฐ
$user_input = "example.com"; // ์ฌ์ฉ์๊ฐ ์
๋ ฅํ ๋๋ฉ์ธ
// ๋์ ์: ์ง์ ์ฌ์ฉ
$bad_pattern = "/$user_input/"; // ์ํ!
// ์ข์ ์: preg_quote๋ก ์ด์ค์ผ์ดํ
$safe_pattern = '/' . preg_quote($user_input, '/') . '/';
// preg_quote ์์
echo preg_quote("example.com"); // example\.com
echo preg_quote("$100.00"); // \$100\.00
echo preg_quote("a+b*c?"); // a\+b\*c\?
// ๊ฒ์์ด ํ์ด๋ผ์ดํธ ์์
function highlightSearch($text, $search) {
$safe_search = preg_quote($search, '/');
return preg_replace("/($safe_search)/i", '<mark>$1</mark>', $text);
}
echo highlightSearch("Hello World", "world");
// Hello <mark>World</mark>
?>
์ฑ๋ฅ ์ต์ ํ ํ
โ /.*@.*/
โ /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/
2. ์ต์ปค ํ์ฉ
^์ $๋ฅผ ์ฌ์ฉํ๋ฉด ๋ถํ์ํ ํ์์ ์ค์ผ ์ ์์ด์.
3. ๋น์บก์ฒ ๊ทธ๋ฃน ์ฌ์ฉ
์บก์ฒ๊ฐ ํ์ ์์ผ๋ฉด (?:...)๋ฅผ ์ฌ์ฉํ์ธ์.
4. ์์ ๊ทธ๋ฃน (Atomic Groups)
(?>...)๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฐฑํธ๋ํน์ ๋ฐฉ์งํ ์ ์์ด์.
5. ๋จ์ํ ๋ฌธ์์ด ํจ์ ์ฐ์ ๊ณ ๋ ค
๊ฐ๋จํ ์์ ์ strpos(), str_replace() ๋ฑ์ด ๋ ๋น ๋ฅผ ์ ์์ด์.
<?php
// ์ฑ๋ฅ ๋น๊ต ์์
$text = str_repeat("Hello World ", 10000);
// ๋ฐฉ๋ฒ 1: ์ ๊ทํํ์
$start = microtime(true);
$count1 = preg_match_all('/World/', $text);
$time1 = microtime(true) - $start;
// ๋ฐฉ๋ฒ 2: substr_count (๋ ๋น ๋ฆ!)
$start = microtime(true);
$count2 = substr_count($text, 'World');
$time2 = microtime(true) - $start;
echo "์ ๊ทํํ์: {$time1}์ด\n";
echo "substr_count: {$time2}์ด\n";
// substr_count๊ฐ ํจ์ฌ ๋น ๋ฆ!
// ์์ ๊ทธ๋ฃน ์์
$pattern_slow = '/(a+)b/'; // ๋ฐฑํธ๋ํน ๋ฐ์
$pattern_fast = '/(?>a+)b/'; // ๋ฐฑํธ๋ํน ๋ฐฉ์ง
// ์ปดํ์ผ๋ ํจํด ์ฌ์ฌ์ฉ
class RegexCache {
private static $cache = [];
public static function match($pattern, $subject) {
if (!isset(self::$cache[$pattern])) {
// ํจํด ๊ฒ์ฆ ๋ฐ ์บ์ฑ
self::$cache[$pattern] = $pattern;
}
return preg_match(self::$cache[$pattern], $subject);
}
}
?>
๐ ์ค์ ํ๋ก์ ํธ: ํ ์คํธ ์ฒ๋ฆฌ ์ ํธ๋ฆฌํฐ ํด๋์ค
์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ด์ฉ์ ์ข
ํฉํด์ ์ค๋ฌด์์ ๋ฐ๋ก ์ธ ์ ์๋
ํ
์คํธ ์ฒ๋ฆฌ ์ ํธ๋ฆฌํฐ ํด๋์ค๋ฅผ ๋ง๋ค์ด๋ณด์! ๐ ๏ธ
์ด๋ฐ ํด๋์ค ํ๋ ๋ง๋ค์ด๋๋ฉด ํ๋ก์ ํธ์์ ๊ณ์ ์ฌ์ฌ์ฉํ ์ ์์ด์ ์ ๋ง ํธํด.
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ํ๋ก์ ํธ ์งํํ ๋๋ ์ ์ฉํ๊ฒ ์ธ ์ ์์ ๊ฑฐ์ผ!
<?php
/**
* ํ
์คํธ ์ฒ๋ฆฌ ์ ํธ๋ฆฌํฐ ํด๋์ค
* ์ ๊ทํํ์์ ํ์ฉํ ๋ค์ํ ํ
์คํธ ๊ฒ์ฆ ๋ฐ ์ฒ๋ฆฌ ๊ธฐ๋ฅ ์ ๊ณต
*/
class TextValidator {
/**
* ์ด๋ฉ์ผ ๊ฒ์ฆ
*/
public static function isValidEmail($email) {
$pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
return preg_match($pattern, $email) === 1;
}
/**
* ํ๊ตญ ํด๋ํฐ ๋ฒํธ ๊ฒ์ฆ
*/
public static function isValidPhone($phone) {
$pattern = '/^01[0-9]-?\d{3,4}-?\d{4}$/';
return preg_match($pattern, $phone) === 1;
}
/**
* ์ ํ๋ฒํธ ํฌ๋งทํ
*/
public static function formatPhone($phone) {
$numbers = preg_replace('/[^0-9]/', '', $phone);
if (preg_match('/^(01[0-9])(\d{3,4})(\d{4})$/', $numbers, $matches)) {
return $matches[1] . '-' . $matches[2] . '-' . $matches[3];
}
if (preg_match('/^(0\d{1,2})(\d{3,4})(\d{4})$/', $numbers, $matches)) {
return $matches[1] . '-' . $matches[2] . '-' . $matches[3];
}
return $phone;
}
/**
* URL ๊ฒ์ฆ
*/
public static function isValidUrl($url) {
$pattern = '/^https?:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/';
return preg_match($pattern, $url) === 1;
}
/**
* ํ
์คํธ์์ URL ์ถ์ถ
*/
public static function extractUrls($text) {
$pattern = '/https?:\/\/[^\s]+/';
preg_match_all($pattern, $text, $matches);
return $matches[0];
}
/**
* ๋น๋ฐ๋ฒํธ ๊ฐ๋ ์ฒดํฌ
*/
public static function checkPasswordStrength($password) {
$patterns = [
'length' => strlen($password) >= 8,
'lowercase' => preg_match('/[a-z]/', $password),
'uppercase' => preg_match('/[A-Z]/', $password),
'number' => preg_match('/\d/', $password),
'special' => preg_match('/[@$!%*?&#]/', $password)
];
$score = array_sum($patterns);
if ($score === 5) return '๋งค์ฐ ๊ฐ๋ ฅ';
if ($score >= 4) return '๊ฐ๋ ฅ';
if ($score >= 3) return '๋ณดํต';
if ($score >= 2) return '์ฝํจ';
return '๋งค์ฐ ์ฝํจ';
}
/**
* HTML ํ๊ทธ ์ ๊ฑฐ (XSS ๋ฐฉ์ง)
*/
public static function stripTags($text, $allowedTags = []) {
if (empty($allowedTags)) {
return preg_replace('/<[^>]+>/', '', $text);
}
$allowed = implode('|', array_map('preg_quote', $allowedTags));
$pattern = '/<(?!\/?(' . $allowed . ')\b)[^>]+>/';
return preg_replace($pattern, '', $text);
}
/**
* ์ด๋ฉ์ผ ๋ง์คํน
*/
public static function maskEmail($email) {
return preg_replace('/^(.{2})[^@]+(@.+)$/', '$1***$2', $email);
}
/**
* ์ ํ๋ฒํธ ๋ง์คํน
*/
public static function maskPhone($phone) {
return preg_replace('/^(\d{3})-?(\d{3,4})-?(\d{4})$/', '$1-****-$3', $phone);
}
/**
* ์ ์ฉ์นด๋ ๋ฒํธ ๋ง์คํน
*/
public static function maskCardNumber($card) {
return preg_replace('/^(\d{4})-?(\d{4})-?(\d{4})-?(\d{4})$/', '****-****-****-$4', $card);
}
/**
* ํ
์คํธ์์ ์ด๋ฉ์ผ ์ถ์ถ
*/
public static function extractEmails($text) {
$pattern = '/[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/';
preg_match_all($pattern, $text, $matches);
return $matches[0];
}
/**
* ํ๊ธ๋ง ์ถ์ถ
*/
public static function extractKorean($text) {
preg_match_all('/[๊ฐ-ํฃ]+/u', $text, $matches);
return implode('', $matches[0]);
}
/**
* ์ซ์๋ง ์ถ์ถ
*/
public static function extractNumbers($text) {
return preg_replace('/[^0-9]/', '', $text);
}
/**
* ์ฌ๋ฌ ๊ณต๋ฐฑ์ ํ๋๋ก
*/
public static function normalizeSpaces($text) {
return preg_replace('/\s+/', ' ', trim($text));
}
/**
* ๊ฒ์์ด ํ์ด๋ผ์ดํธ
*/
public static function highlight($text, $keyword, $tag = 'mark') {
$safe_keyword = preg_quote($keyword, '/');
return preg_replace("/($safe_keyword)/iu", "<{$tag}>$1</{$tag}>", $text);
}
/**
* ๋ ์ง ํ์ ๋ณํ
*/
public static function convertDateFormat($date, $outputFormat = 'Y-m-d') {
// ๋ค์ํ ์
๋ ฅ ํ์ ์ง์
$patterns = [
'/^(\d{4})[.\/-](\d{1,2})[.\/-](\d{1,2})$/' => '$1-$2-$3',
'/^(\d{1,2})[.\/-](\d{1,2})[.\/-](\d{4})$/' => '$3-$1-$2',
];
foreach ($patterns as $pattern => $replacement) {
if (preg_match($pattern, $date)) {
$normalized = preg_replace($pattern, $replacement, $date);
$timestamp = strtotime($normalized);
if ($timestamp !== false) {
return date($outputFormat, $timestamp);
}
}
}
return $date;
}
/**
* ์์ ํ ํ์ผ๋ช
์์ฑ
*/
public static function sanitizeFilename($filename) {
// ํ์ฅ์ ๋ถ๋ฆฌ
$info = pathinfo($filename);
$name = $info['filename'];
$ext = isset($info['extension']) ? '.' . $info['extension'] : '';
// ํน์๋ฌธ์ ์ ๊ฑฐ, ๊ณต๋ฐฑ์ ์ธ๋์ค์ฝ์ด๋ก
$name = preg_replace('/[^a-zA-Z0-9๊ฐ-ํฃ_-]/', '_', $name);
$name = preg_replace('/_+/', '_', $name);
return $name . $ext;
}
/**
* ์ฌ๋ฌ๊ทธ ์์ฑ (URL ์นํ์ ๋ฌธ์์ด)
*/
public static function createSlug($text) {
// ์๋ฌธ์ ๋ณํ
$text = strtolower($text);
// ํน์๋ฌธ์๋ฅผ ํ์ดํ์ผ๋ก
$text = preg_replace('/[^a-z0-9๊ฐ-ํฃ]+/u', '-', $text);
// ์ฐ์๋ ํ์ดํ์ ํ๋๋ก
$text = preg_replace('/-+/', '-', $text);
// ์๋ค ํ์ดํ ์ ๊ฑฐ
return trim($text, '-');
}
}
// ์ฌ์ฉ ์์
echo "=== ์ด๋ฉ์ผ ๊ฒ์ฆ ===\n";
var_dump(TextValidator::isValidEmail("user@example.com")); // true
var_dump(TextValidator::isValidEmail("invalid@")); // false
echo "\n=== ์ ํ๋ฒํธ ํฌ๋งทํ
===\n";
echo TextValidator::formatPhone("01012345678") . "\n"; // 010-1234-5678
echo TextValidator::formatPhone("0212345678") . "\n"; // 02-1234-5678
echo "\n=== ๋น๋ฐ๋ฒํธ ๊ฐ๋ ===\n";
echo TextValidator::checkPasswordStrength("Pass123!") . "\n"; // ๊ฐ๋ ฅ
echo TextValidator::checkPasswordStrength("password") . "\n"; // ์ฝํจ
echo "\n=== ๋ง์คํน ===\n";
echo TextValidator::maskEmail("john.doe@example.com") . "\n"; // jo***@example.com
echo TextValidator::maskPhone("010-1234-5678") . "\n"; // 010-****-5678
echo TextValidator::maskCardNumber("1234-5678-9012-3456") . "\n"; // ****-****-****-3456
echo "\n=== ํ
์คํธ ์ถ์ถ ===\n";
$text = "์ฐ๋ฝ์ฒ: user@example.com, ์ ํ: 010-1234-5678, ๊ฐ๊ฒฉ: 10000์";
print_r(TextValidator::extractEmails($text));
echo TextValidator::extractNumbers($text) . "\n"; // 01012345678 10000
echo "\n=== ํ์ด๋ผ์ดํธ ===\n";
echo TextValidator::highlight("Hello World", "world") . "\n";
// Hello <mark>World</mark>
echo "\n=== ์ฌ๋ฌ๊ทธ ์์ฑ ===\n";
echo TextValidator::createSlug("์๋
ํ์ธ์! PHP ์ ๊ทํํ์") . "\n";
// ์๋
ํ์ธ์-php-์ ๊ทํํ์
?>
- ํ์๊ฐ์ ํผ ๊ฒ์ฆ
- ๊ฒ์ํ ์ ๋ ฅ๊ฐ ์ ์
- ๊ฒ์ ๊ธฐ๋ฅ ๊ตฌํ
- ๋ฐ์ดํฐ ๋ง์คํน ์ฒ๋ฆฌ
- ํ์ผ ์ ๋ก๋ ๊ฒ์ฆ
๋ฑ ๋ค์ํ ๊ณณ์์ ๋ฐ๋ก ํ์ฉํ ์ ์์ด์!
์ฌ๋ฅ๋ท์์ ํ๋ก์ ํธ ์๋ขฐ๋ฐ์ ๋๋ ์ด๋ฐ ์ ํธ๋ฆฌํฐ ํด๋์ค๊ฐ ์์ผ๋ฉด ๊ฐ๋ฐ ์๋๊ฐ ํจ์ฌ ๋นจ๋ผ์ ธ์!
๐ ๋๋ฒ๊น ๊ณผ ํ ์คํธ
์ ๊ทํํ์์ ๋ณต์กํด์ ๋๋ฒ๊น
์ด ์ด๋ ค์ธ ์ ์์ด.
ํจ๊ณผ์ ์ผ๋ก ํ
์คํธํ๊ณ ๋๋ฒ๊น
ํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด์! ๐
์ ๊ทํํ์ ํ ์คํธ ๋๊ตฌ
- ์ค์๊ฐ ๋งค์นญ ๊ฒฐ๊ณผ
- ์์ธํ ์ค๋ช
- ๋ค์ํ ์ธ์ด ์ง์ (PHP PCRE ํฌํจ)
2. regexr.com - ์๊ฐ์ ์ผ๋ก ๋ณด๊ธฐ ์ข์ ์ธํฐํ์ด์ค
- ์ปค๋ฎค๋ํฐ ํจํด ๊ณต์
- ์นํธ์ํธ ์ ๊ณต
3. regexpal.com - ๊ฐ๋จํ๊ณ ๋น ๋ฅธ ํ ์คํธ
PHP ์ฝ๋๋ก ํ ์คํธํ ๋๋ ํญ์ ๋ค์ํ ์ผ์ด์ค๋ฅผ ์ค๋นํ์ธ์!
์๋ฌ ์ฒ๋ฆฌ์ ๋๋ฒ๊น
<?php
/**
* ์ ๊ทํํ์ ์๋ฌ ์ฒ๋ฆฌ ํฌํผ ํจ์
*/
function safePreg($function, ...$args) {
$result = @$function(...$args);
if ($result === false) {
$error_code = preg_last_error();
$errors = [
PREG_NO_ERROR => '์๋ฌ ์์',
PREG_INTERNAL_ERROR => '๋ด๋ถ PCRE ์๋ฌ',
PREG_BACKTRACK_LIMIT_ERROR => '๋ฐฑํธ๋ ์ ํ ์ด๊ณผ',
PREG_RECURSION_LIMIT_ERROR => '์ฌ๊ท ์ ํ ์ด๊ณผ',
PREG_BAD_UTF8_ERROR => '์๋ชป๋ UTF-8 ๋ฐ์ดํฐ',
PREG_BAD_UTF8_OFFSET_ERROR => '์๋ชป๋ UTF-8 ์คํ์
',
];
$error_msg = $errors[$error_code] ?? '์ ์ ์๋ ์๋ฌ';
throw new Exception("์ ๊ทํํ์ ์๋ฌ: {$error_msg}");
}
return $result;
}
// ์ฌ์ฉ ์์
try {
$pattern = '/[a-z]+/';
$text = "Hello World";
$result = safePreg('preg_match', $pattern, $text);
echo "๋งค์นญ ๊ฒฐ๊ณผ: {$result}\n";
} catch (Exception $e) {
echo "์๋ฌ ๋ฐ์: " . $e->getMessage() . "\n";
}
/**
* ์ ๊ทํํ์ ํจํด ๊ฒ์ฆ
*/
function validatePattern($pattern) {
$test = @preg_match($pattern, '');
if ($test === false) {
$error = error_get_last();
return [
'valid' => false,
'error' => $error['message'] ?? '์ ์ ์๋ ์๋ฌ'
];
}
return ['valid' => true];
}
// ํจํด ๊ฒ์ฆ ์์
$patterns = [
'/[a-z]+/' => '์ฌ๋ฐ๋ฅธ ํจํด',
'/[a-z/' => '๋ซ๋ ๊ดํธ ๋๋ฝ',
'/(?P<name>[a-z]+)/' => '๋ช
๋ช
๋ ๊ทธ๋ฃน',
];
foreach ($patterns as $pattern => $desc) {
$result = validatePattern($pattern);
echo "{$desc}: " . ($result['valid'] ? 'โ' : 'โ') . "\n";
if (!$result['valid']) {
echo " ์๋ฌ: {$result['error']}\n";
}
}
/**
* ์ ๊ทํํ์ ์ฑ๋ฅ ์ธก์
*/
function benchmarkRegex($pattern, $text, $iterations = 1000) {
$start = microtime(true);
for ($i = 0; $i < $iterations; $i++) {
preg_match($pattern, $text);
}
$elapsed = microtime(true) - $start;
$avg = $elapsed / $iterations * 1000; // ๋ฐ๋ฆฌ์ด
return [
'total' => $elapsed,
'average' => $avg,
'iterations' => $iterations
];
}
// ์ฑ๋ฅ ๋น๊ต
$text = str_repeat("Hello World ", 100);
$patterns = [
'Simple' => '/World/',
'Complex' => '/\b[A-Z][a-z]+\b/',
'Lookahead' => '/\b(?=\w{5})\w+\b/',
];
echo "\n=== ์ฑ๋ฅ ๋ฒค์น๋งํฌ ===\n";
foreach ($patterns as $name => $pattern) {
$result = benchmarkRegex($pattern, $text);
printf("%s: %.4f ms (ํ๊ท )\n", $name, $result['average']);
}
/**
* ์ ๋ ํ
์คํธ ์์
*/
class RegexTest {
private $passed = 0;
private $failed = 0;
public function test($name, $pattern, $text, $expected) {
$result = preg_match($pattern, $text);
$success = ($result === 1) === $expected;
if ($success) {
$this->passed++;
echo "โ {$name}\n";
} else {
$this->failed++;
echo "โ {$name}\n";
echo " ์์: " . ($expected ? '๋งค์นญ' : '๋ถ์ผ์น') . "\n";
echo " ์ค์ : " . ($result ? '๋งค์นญ' : '๋ถ์ผ์น') . "\n";
}
}
public function summary() {
$total = $this->passed + $this->failed;
echo "\n=== ํ
์คํธ ๊ฒฐ๊ณผ ===\n";
echo "ํต๊ณผ: {$this->passed}/{$total}\n";
echo "์คํจ: {$this->failed}/{$total}\n";
}
}
// ์ด๋ฉ์ผ ๊ฒ์ฆ ํ
์คํธ
$tester = new RegexTest();
$email_pattern = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
echo "\n=== ์ด๋ฉ์ผ ๊ฒ์ฆ ํ
์คํธ ===\n";
$tester->test('์ ํจํ ์ด๋ฉ์ผ 1', $email_pattern, 'user@example.com', true);
$tester->test('์ ํจํ ์ด๋ฉ์ผ 2', $email_pattern, 'test.user@sub.domain.co.kr', true);
$tester->test('๋ฌดํจํ ์ด๋ฉ์ผ 1', $email_pattern, 'invalid@', false);
$tester->test('๋ฌดํจํ ์ด๋ฉ์ผ 2', $email_pattern, '@example.com', false);
$tester->test('๋ฌดํจํ ์ด๋ฉ์ผ 3', $email_pattern, 'user@.com', false);
$tester->summary();
?>
๐ ์ค๋ฌด ํจํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ
์์ฃผ ์ฌ์ฉํ๋ ์ ๊ทํํ์ ํจํด๋ค์ ๋ชจ์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ๋ง๋ค์ด๋ดค์ด.
๋ณต์ฌํด์ ๋ฐ๋ก ์ธ ์ ์๊ฒ ์ฃผ์๋ ์์ธํ ๋ฌ์๋์ผ๋๊น ํ์ฉํด๋ด! ๐
<?php
/**
* ์ ๊ทํํ์ ํจํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ
*/
class RegexPatterns {
// ===== ๊ธฐ๋ณธ ๊ฒ์ฆ =====
/** ์ด๋ฉ์ผ (๊ธฐ๋ณธ) */
const EMAIL = '/^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
/** ์ด๋ฉ์ผ (์๊ฒฉ) */
const EMAIL_STRICT = '/^(?!.*\.\.)(?!.*\.$)[a-zA-Z0-9._%+-]{1,64}@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/';
/** URL (http/https) */
const URL = '/^https?:\/\/[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}(\/[^\s]*)?$/';
/** URL (ํ๋กํ ์ฝ ์ ํ) */
const URL_FLEXIBLE = '/^(https?|ftp):\/\/[^\s]+$/';
// ===== ์ ํ๋ฒํธ =====
/** ํ๊ตญ ํด๋ํฐ (ํ์ดํ ํ์) */
const PHONE_KR_MOBILE = '/^01[0-9]-\d{3,4}-\d{4}$/';
/** ํ๊ตญ ํด๋ํฐ (ํ์ดํ ์ ํ) */
const PHONE_KR_MOBILE_FLEX = '/^01[0-9]-?\d{3,4}-?\d{4}$/';
/** ํ๊ตญ ์ผ๋ฐ์ ํ */
const PHONE_KR_LANDLINE = '/^0\d{1,2}-\d{3,4}-\d{4}$/';
/** ๊ตญ์ ์ ํ๋ฒํธ */
const PHONE_INTERNATIONAL = '/^\+[1-9]\d{1,14}$/';
// ===== ๋น๋ฐ๋ฒํธ =====
/** ๋น๋ฐ๋ฒํธ (8์ ์ด์, ์๋ฌธ+์ซ์) */
const PASSWORD_MEDIUM = '/^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$/';
/** ๋น๋ฐ๋ฒํธ (8์ ์ด์, ์๋ฌธ ๋์๋ฌธ์+์ซ์+ํน์๋ฌธ์) */
const PASSWORD_STRONG = '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/';
/** ๋น๋ฐ๋ฒํธ (10์ ์ด์, ๋ชจ๋ ์กฐ๊ฑด) */
const PASSWORD_VERY_STRONG = '/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&#])[A-Za-z\d@$!%*?&#]{10,}$/';
// ===== ๋ ์ง/์๊ฐ =====
/** ๋ ์ง (YYYY-MM-DD) */
const DATE_ISO = '/^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$/';
/** ๋ ์ง (YYYY.MM.DD ๋๋ YYYY/MM/DD) */
const DATE_FLEXIBLE = '/^\d{4}[.\/-](0[1-9]|1[0-2])[.\/-](0[1-9]|[12]\d|3[01])$/';
/** ์๊ฐ (HH:MM) */
const TIME_24H = '/^([01]\d|2[0-3]):[0-5]\d$/';
/** ์๊ฐ (HH:MM:SS) */
const TIME_24H_FULL = '/^([01]\d|2[0-3]):[0-5]\d:[0-5]\d$/';
/** ๋ ์ง+์๊ฐ (ISO 8601) */
const DATETIME_ISO = '/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/';
// ===== ์ซ์ =====
/** ์ ์ */
const INTEGER = '/^-?\d+$/';
/** ์์ ์ ์ */
const POSITIVE_INTEGER = '/^\d+$/';
/** ์์ */
const DECIMAL = '/^-?\d+(\.\d+)?$/';
/** ํตํ (์ํ) */
const CURRENCY_KRW = '/^\d{1,3}(,\d{3})*์?$/';
/** ํตํ (๋ฌ๋ฌ) */
const CURRENCY_USD = '/^\$\d{1,3}(,\d{3})*(\.\d{2})?$/';
/** ํผ์ผํธ */
const PERCENTAGE = '/^\d+(\.\d+)?%$/';
// ===== ํ๊ตญ ํนํ =====
/** ํ๊ธ๋ง */
const KOREAN_ONLY = '/^[๊ฐ-ํฃ]+$/u';
/** ํ๊ธ+์๋ฌธ */
const KOREAN_ENGLISH = '/^[๊ฐ-ํฃa-zA-Z]+$/u';
/** ํ๊ธ+์๋ฌธ+์ซ์ */
const KOREAN_ENGLISH_NUMBER = '/^[๊ฐ-ํฃa-zA-Z0-9]+$/u';
/** ์ฐํธ๋ฒํธ (5์๋ฆฌ) */
const ZIPCODE_KR = '/^\d{5}$/';
/** ์ฐํธ๋ฒํธ (๊ตฌํ 6์๋ฆฌ) */
const ZIPCODE_KR_OLD = '/^\d{3}-?\d{3}$/';
/** ์ฃผ๋ฏผ๋ฑ๋ก๋ฒํธ */
const JUMIN = '/^\d{6}-?[1-4]\d{6}$/';
/** ์ฌ์
์๋ฑ๋ก๋ฒํธ */
const BUSINESS_NUMBER = '/^\d{3}-?\d{2}-?\d{5}$/';
// ===== ์ ์ฉ์นด๋ =====
/** ์ ์ฉ์นด๋ ๋ฒํธ */
const CREDIT_CARD = '/^\d{4}-?\d{4}-?\d{4}-?\d{4}$/';
/** Visa */
const VISA = '/^4\d{3}-?\d{4}-?\d{4}-?\d{4}$/';
/** MasterCard */
const MASTERCARD = '/^5[1-5]\d{2}-?\d{4}-?\d{4}-?\d{4}$/';
/** American Express */
const AMEX = '/^3[47]\d{2}-?\d{6}-?\d{5}$/';
// ===== IP ์ฃผ์ =====
/** IPv4 */
const IPV4 = '/^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)$/';
/** IPv6 (๊ฐ๋จ) */
const IPV6 = '/^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/';
// ===== ํ์ผ =====
/** ์ด๋ฏธ์ง ํ์ผ ํ์ฅ์ */
const IMAGE_FILE = '/\.(jpg|jpeg|png|gif|bmp|svg|webp)$/i';
/** ๋ฌธ์ ํ์ผ ํ์ฅ์ */
const DOCUMENT_FILE = '/\.(pdf|doc|docx|xls|xlsx|ppt|pptx|txt)$/i';
/** ์์ถ ํ์ผ ํ์ฅ์ */
const ARCHIVE_FILE = '/\.(zip|rar|7z|tar|gz)$/i';
// ===== HTML/XML =====
/** HTML ํ๊ทธ */
const HTML_TAG = '/<[^>]+>/';
/** HTML ์ฃผ์ */
const HTML_COMMENT = '/<!--.*?-->/s';
/** XML ํ๊ทธ */
const XML_TAG = '/<\/?[\w\s="\']+>/';
// ===== ์์
๋ฏธ๋์ด =====
/** ํด์ํ๊ทธ */
const HASHTAG = '/#[\w๊ฐ-ํฃ]+/u';
/** ๋ฉ์
(@username) */
const MENTION = '/@[\w๊ฐ-ํฃ]+/u';
/** ํธ์ํฐ ์ฌ์ฉ์๋ช
*/
const TWITTER_USERNAME = '/^@?[A-Za-z0-9_]{1,15}$/';
/** ์ธ์คํ๊ทธ๋จ ์ฌ์ฉ์๋ช
*/
const INSTAGRAM_USERNAME = '/^@?[A-Za-z0-9_.]{1,30}$/';
// ===== ๊ธฐํ =====
/** 16์ง์ ์์ ์ฝ๋ */
const HEX_COLOR = '/^#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/';
/** MAC ์ฃผ์ */
const MAC_ADDRESS = '/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/';
/** UUID */
const UUID = '/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i';
/** Base64 */
const BASE64 = '/^[A-Za-z0-9+\/]*={0,2}$/';
/**
* ํจํด ๊ฒ์ฆ ํฌํผ
*/
public static function validate($pattern, $text) {
return preg_match($pattern, $text) === 1;
}
/**
* ์ฌ๋ฌ ํจํด ์ค ํ๋๋ผ๋ ๋งค์นญ๋๋์ง ํ์ธ
*/
public static function validateAny($patterns, $text) {
foreach ($patterns as $pattern) {
if (self::validate($pattern, $text)) {
return true;
}
}
return false;
}
/**
* ๋ชจ๋ ํจํด์ด ๋งค์นญ๋๋์ง ํ์ธ
*/
public static function validateAll($patterns, $text) {
foreach ($patterns as $pattern) {
if (!self::validate($pattern, $text)) {
return false;
}
}
return true;
}
}
// ์ฌ์ฉ ์์
echo "=== ํจํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ฌ์ฉ ์์ ===\n\n";
// ์ด๋ฉ์ผ ๊ฒ์ฆ
$email = "user@example.com";
echo "์ด๋ฉ์ผ ๊ฒ์ฆ: ";
echo RegexPatterns::validate(RegexPatterns::EMAIL, $email) ? "โ" : "โ";
echo "\n";
// ์ ํ๋ฒํธ ๊ฒ์ฆ
$phone = "010-1234-5678";
echo "์ ํ๋ฒํธ ๊ฒ์ฆ: ";
echo RegexPatterns::validate(RegexPatterns::PHONE_KR_MOBILE, $phone) ? "โ" : "โ";
echo "\n";
// ๋น๋ฐ๋ฒํธ ๊ฐ๋ ์ฒดํฌ
$password = "Pass123!";
echo "๋น๋ฐ๋ฒํธ ๊ฐ๋: ";
if (RegexPatterns::validate(RegexPatterns::PASSWORD_VERY_STRONG, $password)) {
echo "๋งค์ฐ ๊ฐ๋ ฅ";
} elseif (RegexPatterns::validate(RegexPatterns::PASSWORD_STRONG, $password)) {
echo "๊ฐ๋ ฅ";
} elseif (RegexPatterns::validate(RegexPatterns::PASSWORD_MEDIUM, $password)) {
echo "๋ณดํต";
} else {
echo "์ฝํจ";
}
echo "\n";
// ๋ ์ง ํ์ ์ฒดํฌ
$date = "2024-03-15";
echo "๋ ์ง ํ์: ";
echo RegexPatterns::validate(RegexPatterns::DATE_ISO, $date) ? "โ" : "โ";
echo "\n";
// ํ๊ธ ์ด๋ฆ ์ฒดํฌ
$name = "ํ๊ธธ๋";
echo "ํ๊ธ ์ด๋ฆ: ";
echo RegexPatterns::validate(RegexPatterns::KOREAN_ONLY, $name) ? "โ" : "โ";
echo "\n";
// URL ์ฒดํฌ
$url = "https://www.example.com";
echo "URL ํ์: ";
echo RegexPatterns::validate(RegexPatterns::URL, $url) ? "โ" : "โ";
echo "\n";
?>
๐ฏ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์, ์ฌ๊ธฐ๊น์ง ์ฝ์๋ค๋ฉด ์ ๋ง ๋๋จํด! ๐
PHP ์ ๊ทํํ์๊ณผ PCRE์ ๋ํด ๊ฝค ๋ง์ ๊ฑธ ๋ฐฐ์ ์ ๊ฑฐ์ผ.
์ ๊ทํํ์์ ์ฒ์์ ์ด๋ ต๊ฒ ๋๊ปด์ง์ง๋ง, ๊ณ์ ์ฐ๋ค ๋ณด๋ฉด ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ๋ผ๋ ๊ฑธ ์๊ฒ ๋ ๊ฑฐ์ผ.
ํนํ ํ
์คํธ ์ฒ๋ฆฌ๊ฐ ๋ง์ ์น ๊ฐ๋ฐ์์๋ ํ์ ์คํฌ์ด๋ผ๊ณ ํ ์ ์์ง. ๐ช
์ฌ๋ฅ๋ท ๊ฐ์ ํ๋ซํผ์์ ํ๋ก์ ํธ๋ฅผ ์งํํ๊ฑฐ๋,
๊ฐ์ธ ํ๋ก์ ํธ๋ฅผ ๋ง๋ค ๋๋ ์ค๋ ๋ฐฐ์ด ๋ด์ฉ๋ค์ด ํฐ ๋์์ด ๋ ๊ฑฐ์ผ!
- ์ ๊ทํํ์์ ํ ์คํธ ํจํด์ ํํํ๋ ํ์ ์ธ์ด
- PHP๋ PCRE ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉ (preg_ ํจ์๊ตฐ)
- ๋ฉํ๋ฌธ์, ์๋์, ๋ฌธ์ ํด๋์ค๋ก ํจํด ๊ตฌ์ฑ
2. ์ฃผ์ ํจ์
- preg_match(): ํจํด ๋งค์นญ ํ์ธ
- preg_match_all(): ๋ชจ๋ ๋งค์นญ ์ฐพ๊ธฐ
- preg_replace(): ํจํด ์นํ
- preg_split(): ํจํด์ผ๋ก ๋ถํ
3. ๊ณ ๊ธ ๊ธฐ๋ฅ
- ์บก์ฒ ๊ทธ๋ฃน๊ณผ ์ญ์ฐธ์กฐ
- Lookahead/Lookbehind
- ํ๋๊ทธ๋ก ๋์ ์ ์ด
- ์์ ๊ทธ๋ฃน์ผ๋ก ์ฑ๋ฅ ์ต์ ํ
4. ์ค๋ฌด ํ
- ๋ณด์: ReDoS ๊ณต๊ฒฉ ์ฃผ์, ์ ๋ ฅ๊ฐ ์ด์ค์ผ์ดํ
- ์ฑ๋ฅ: ๊ตฌ์ฒด์ ํจํด, ์ต์ปค ํ์ฉ, ๋น์บก์ฒ ๊ทธ๋ฃน
- ํ ์คํธ: ๋ค์ํ ์ผ์ด์ค, ์๋ฌ ์ฒ๋ฆฌ
- ์ ์ง๋ณด์: ํจํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ, ์ฃผ์ ํ์ฉ
์ ๊ทํํ์์ ์ฐ์ต์ด ์ ๋ง ์ค์ํด.
์ค๋ ๋ฐฐ์ด ์์ ๋ค์ ์ง์ ์คํํด๋ณด๊ณ , ์์ ๋ง์ ํจํด๋ ๋ง๋ค์ด๋ณด๋ฉด์ ์ตํ๋ด!
๋งํ๋ ๋ถ๋ถ์ด ์์ผ๋ฉด regex101.com ๊ฐ์ ์จ๋ผ์ธ ๋๊ตฌ๋ฅผ ํ์ฉํ๋ฉด ์ข์.
์ค์๊ฐ์ผ๋ก ํจํด์ ํ
์คํธํ๊ณ ์ค๋ช
๋ ๋ณผ ์ ์๊ฑฐ๋ . ๐ ๏ธ
๊ทธ๋ฆฌ๊ณ ๊ธฐ์ตํด, ๋ชจ๋ ๋ฌธ์ ๋ฅผ ์ ๊ทํํ์์ผ๋ก ํด๊ฒฐํ๋ ค๊ณ ํ์ง ๋ง!
๊ฐ๋จํ ์์
์ strpos(), str_replace() ๊ฐ์ ํจ์๊ฐ ๋ ๋น ๋ฅด๊ณ ์ฝ๊ธฐ ์ฌ์ธ ์ ์์ด.
์, ์ด์ ์ค์ ์์ ๋ง์๊ป ํ์ฉํด๋ด!
ํ์ดํ
! ๐โจ
๐ ์๊ณ ํ์
จ์ต๋๋ค! ๐
PHP ์ ๊ทํํ์ ๋ง์คํฐ์ ๊ธธ์ ํฅํด ํ ๊ฑธ์ ๋ ๋์๊ฐ์ด์!
๊ณ์ ์ฐ์ตํ๊ณ ์ค์ ์ ์ ์ฉํด๋ณด์ธ์.
๋ ๋ง์ ๊ฐ๋ฐ ์ง์์ด ํ์ํ๋ค๋ฉด ์ฌ๋ฅ๋ท์์
๋ค์ํ ์ ๋ฌธ๊ฐ๋ค๊ณผ ์ํตํด๋ณด์ธ์!
๊ด๋ จ ํค์๋
๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.
์์ง ๋๊ธ์ด ์์ต๋๋ค.