정규 표현식이란 정확히 무엇인가요? 다음 PHP 중국어 웹사이트에서는 정규식을 소개합니다. [추천 자료: 정규식 동영상 튜토리얼]
문자열을 처리하는 프로그램이나 웹페이지를 작성할 때 특정 복잡한 규칙과 일치하는 문자열을 찾아야 하는 경우가 종종 있습니다. 정규식은 이러한 규칙을 설명하는 데 사용되는 도구입니다. 즉, 정규식은 텍스트 규칙을 기록하는 코드입니다.
Windows/Dos에서 파일 검색에 와일드카드, 즉 * 및 ?를 사용했을 가능성이 높습니다. 특정 디렉터리에 있는 모든 Word 문서를 찾으려면 *.doc를 검색하면 됩니다. 여기서 *는 임의의 문자열로 해석됩니다. 와일드카드와 유사하게 정규식도 텍스트 일치에 사용되는 도구이지만 와일드카드보다 요구 사항을 더 정확하게 설명할 수 있습니다. 물론 더 복잡해지는 대가를 치르게 됩니다. 예를 들어 정규식을 작성하여 모든 항목을 찾는 데 사용됩니다. 0으로 시작하는 문자열, 2~3자리 숫자, 하이픈 "-", 마지막으로 7~8자리 숫자로 구성됩니다.
시작하기
정규식을 배우는 가장 좋은 방법은 예제를 이해한 후 직접 수정하고 실험해 보는 것입니다. 아래에는 여러 가지 간단한 예가 나와 있으며 자세히 설명되어 있습니다.
영어 소설에서 hi를 검색한다고 가정하면 정규 표현식 hi를 사용할 수 있습니다.
이것은 거의 가장 간단한 정규 표현식입니다. 다음과 같이 문자열을 정확하게 일치시킬 수 있습니다. 두 문자로 구성되며 첫 번째 문자는 h이고 다음 문자는 i입니다. 일반적으로 정규식을 처리하는 도구는 대소문자를 무시하는 옵션을 제공합니다. 이 옵션을 선택하면 hi, HI, Hi 및 hI의 네 가지 대소문자 중 하나와 일치할 수 있습니다.
안타깝게도 그 사람, 역사, 높음 등 '안녕'이라는 두 글자가 연속으로 포함된 단어가 많습니다. hi를 사용하여 검색하면 안에 있는 hi도 검색됩니다. hi라는 단어를 정확하게 찾으려면 bhib를 사용해야 합니다.
b는 단어의 경계인 단어의 시작이나 끝을 나타내는 정규식(글쎄, 어떤 사람들은 메타문자라고 부르기도 함)으로 지정되는 특수 코드입니다. 영어 단어는 일반적으로 공백, 구두점 또는 줄 바꿈으로 구분되지만 b는 이러한 단어 구분 문자와 일치하지 않고 한 위치에만 일치합니다.
안녕하고 멀지 않은 루시를 찾고 있다면 bhib을 이용하세요.*bLucyb.
여기서 .는 개행 문자를 제외한 모든 문자와 일치하는 또 다른 메타 문자입니다. *도 메타 문자이지만 문자나 위치가 아니라 수량을 나타냅니다. * 앞의 내용을 여러 번 반복하여 전체 표현식을 일치시킬 수 있음을 지정합니다. 따라서 .*는 개행 문자를 포함하지 않는 문자 수를 의미합니다. 이제 bhib.*bLucyb의 의미는 분명합니다. 먼저 hi라는 단어가 나오고 그 다음에는 임의 개수의 문자(개행 문자는 제외), 마지막으로 Lucy라는 단어가 나옵니다.
다른 메타 문자를 동시에 사용하면 더욱 강력한 정규식을 구성할 수 있습니다. 예를 들어, 다음 예:
0dd-dddddddd는 0으로 시작하고 두 자리 숫자, 하이픈 "-", 마지막으로 8자리(즉, 중국의 전화번호)로 구성된 문자열과 일치합니다. 물론 이 예는 지역번호가 3자리인 상황에 맞춰주세요)
여기서 d는 한 숫자(0, 1, 2, 또는...)와 일치하는 새로운 메타 문자입니다. - 은(는) 메타 문자가 아니며 하이픈(또는 빼기 기호, 대시 또는 원하는 이름) 자체와만 일치합니다.
너무 많은 귀찮은 반복을 피하기 위해 이 표현식을 다음과 같이 쓸 수도 있습니다: 0d{2}-d{8}. 여기서 d 뒤의 {2}({8})는 이전 d가 연속으로 2번(8번) 반복되어 일치해야 함을 의미합니다.
정규식 테스트
정규식을 읽고 쓰는 것이 어렵지 않다면 당신은 천재이거나 지구인이 아닙니다. 정규식의 구문은 정기적으로 사용하는 사람에게도 혼란스러울 수 있습니다. 읽고 쓰기가 어렵고 오류가 발생하기 쉽기 때문에 정규식을 테스트할 수 있는 도구를 찾는 것이 필요합니다.
정규식의 일부 세부 사항은 환경에 따라 다릅니다. 이 튜토리얼에서는 Microsoft .Net Framework 4.5에서 정규식의 동작을 소개합니다. 따라서 제가 작성한 .Net의 Regester 도구를 추천합니다. 소프트웨어를 설치하고 실행하려면 이 페이지의 지침을 참조하십시오.
다음은 Regester 실행의 스크린샷입니다.
메타 문자
이제 여러분은 b,.,*, d와 같은 몇 가지 유용한 메타 문자를 이미 알고 있습니다. 정규 표현식에는 s와 같은 여러 메타 문자가 더 있습니다. , 공백, 탭, 개행, 중국어 전폭 공백 등을 포함한 모든 공백 문자와 일치합니다. w는 문자, 숫자, 밑줄, 한자 등과 일치합니다.
다음은 몇 가지 예입니다.
baw*b는 문자 a로 시작하는 단어와 일치합니다. 먼저 단어의 시작(b), 문자 a, 임의 개수의 문자 또는 숫자(w *), 마지막으로 단어의 끝 (b).
d+는 1개 이상의 연속 숫자와 일치합니다. 여기서 +는 *와 유사한 메타 문자입니다. 차이점은 *는 여러 번(아마도 0회) 반복되는 것과 일치하는 반면, +는 1회 이상 반복되는 것과 일치한다는 것입니다.
bw{6}b는 정확히 6자로 구성된 단어와 일치합니다.
메타 문자 ^(숫자 6과 동일한 키 위치에 있는 기호) 및 $는 모두 한 위치와 일치하며 이는 b와 다소 유사합니다. ^는 찾고 있는 문자열의 시작 부분과 일치하고 $는 끝 부분과 일치합니다. 이 두 코드는 입력 내용을 확인할 때 매우 유용합니다. 예를 들어 웹 사이트에서 QQ 번호를 5~12자리로 입력해야 하는 경우 ^d{5,12}$를 사용할 수 있습니다.
여기서 {5,12}는 이전에 소개된 {2}와 유사합니다. 단, {2} 일치는 더 이상 또는 그 이하도 없이 2번만 반복할 수 있지만 {5,12 }는 반복 횟수가 5회 미만일 수 없으며 12회 이하여야 합니다. 그렇지 않으면 일치하지 않습니다.
^ 및 $를 사용하므로 전체 입력 문자열을 사용하여 d{5,12}와 일치해야 합니다. 이는 전체 입력이 5~12개의 숫자여야 한다는 의미이므로 입력된 QQ를 입력한 경우 숫자가 이 정규식과 일치할 수 있으면 요구 사항을 충족합니다.
대소문자 무시 옵션과 유사하게 일부 정규식 처리 도구에는 여러 줄을 처리하는 옵션도 있습니다. 이 옵션을 선택하면 ^와 $의 의미가 일치하는 줄의 시작과 끝이 됩니다.
Character escape
메타 문자 자체를 찾으려는 경우, 예를 들어 . 또는 *를 검색하면 지정할 수 없다는 문제가 있습니다. , 다른 의미로 해석되기 때문입니다. 이때 해당 문자의 특별한 의미를 취소하기 위해 사용해야 합니다. 따라서 . 및 *를 사용해야 합니다. 물론 자체적으로 검색하려면 \.
도 사용해야 합니다. 예를 들어 deerchao.net은 deerchao.net과 일치하고 C:\Windows는 C:Windows와 일치합니다.
Repeat
반복을 일치시키는 이전 *, +, {2}, {5,12} 방법을 이미 살펴보았습니다. 다음은 정규식의 모든 한정자입니다(*, {5,12} 등의 지정된 코드 수). some 반복 사용 예:
Windowsd+는 Windows 뒤에 하나 이상의 숫자가 오는 것과 일치합니다.
^w+는 줄의 첫 번째 단어(또는 전체 문자열의 첫 번째 단어와 일치합니다. 구체적인 일치 의미는 옵션 설정에 따라 다름) Character class숫자, 문자 또는 숫자, 공백은 이미 해당 항목이 있으므로 찾는 것은 매우 간단합니다. 문자 세트가 있지만 미리 정의된 메타 문자(예: 모음 a, e, i, o, u) 없이 문자 세트를 일치시키려면 어떻게 해야 합니까? 매우 간단합니다. 대괄호 안에 나열하면 됩니다. 예를 들어 [aeiou]는 모든 영어 모음과 일치하고 [.?!]는 구두점(. 또는 ? 또는 !)과 일치합니다. 문자 범위도 쉽게 지정할 수 있습니다. [0-9]로 표시되는 의미는 d: 한 자리 숫자와 유사하게 [a-z0-9A-Z_]와도 동일합니다. w(영어만 고려하는 경우). 몇 가지 분석을 해보겠습니다. 먼저 이스케이프 문자가 있습니다(0 또는 1번 나타날 수 있음(?). 그런 다음 0이 있고 그 뒤에 숫자 2개가 나옵니다(d{2 }). , ) 또는 - 또는 1회 표시되거나 표시되지 않는 공백(?) 중 하나, 그리고 마지막으로 8자리(d{8})입니다. 분기 조건안타깝게도 지금의 표현식은 010)12345678 또는 (022-87654321)과 같은 "잘못된" 형식과도 일치할 수 있습니다. 분기 조건을 사용하려면 여러 규칙을 참조해야 합니다. 규칙 중 하나라도 일치하면 서로 다른 규칙을 구분하는 것입니다. 상관없습니다. 예를 살펴보세요. 0d{2}-d{8}|0d{3}-d{7} 이 표현식은 하이픈으로 구분된 두 개의 전화번호와 일치할 수 있습니다. 하나는 지역번호 3자리와 지역번호 8자리(예: 010-12345678)이고, 다른 하나는 지역번호 4자리와 지역번호 7자리(0376-2233445)입니다.# 🎜🎜#(0d{2}).)[- ]?d{8}|0d{2}[- ]?d{8} 이 표현식은 지역 번호가 3자리인 전화번호와 일치합니다. 지역 코드 및 지역 코드 공백은 하이픈이나 공백으로 구분할 수 있으며, 공백이 없어도 됩니다. 이 표현식을 확장하여 4자리 지역 코드도 지원하도록 할 수 있습니다. #🎜 🎜##d{5}-d{4.}|d{5} 이 표현식은 미국의 우편번호를 일치시키는 데 사용됩니다. 미국의 우편번호 규칙은 5자리 또는 9자리 구분입니다. 이 예는 문제를 설명할 수 있기 때문에 제공됩니다. : 분기 조건을 사용할 때 각 조건의 순서를 d{5}|d{5}-d{4}로 변경하면 주의하세요. 우편번호 5자리(우편번호 9자리)만 일치하게 됩니다. 그 이유는 지점 조건 일치 시 특정 지점이 충족되면 각 조건이 왼쪽에서 오른쪽으로 테스트되기 때문입니다.
Group
우리는 이미 단일 문자를 반복하는 방법을 언급했습니다(문자 뒤에 한정자를 추가하면 됩니다). 여러 문자를 반복하시겠습니까? 괄호를 사용하여 하위 표현식(그룹화라고도 함)을 지정한 다음 이 하위 표현식의 반복 횟수를 지정할 수 있으며 하위 표현식에 대해 다른 작업을 수행할 수도 있습니다(나중에 소개됩니다) .
(d{1,3}.){3}d{1,3}는 간단한 IP 주소 일치 표현식입니다. 이 표현식을 이해하려면 다음 순서로 분석하세요. d{1,3}은 1~3자리 숫자와 일치하고, (d{1,3}.){3}은 세 자리 숫자에 마침표를 더한 것과 일치합니다(이것은 전체가 이 그룹)을 세 번 반복하고 마지막으로 1~3자리 숫자(d{1,3})가 추가됩니다.
아쉽게도 불가능한 IP 주소 256.300.888.999도 일치하게 됩니다. 산술 비교를 사용할 수 있으면 이 문제를 간단하게 해결할 수 있지만 정규식은 수학 함수를 제공하지 않으므로 긴 그룹화, 선택 및 문자 클래스만 사용하여 올바른 IP 주소를 설명할 수 있습니다.( (2 [0-4]d|25[0-5]|[01]?dd?).){3}(2[0-4]d|25[0-5]|[01]?dd?).
이 표현을 이해하는 열쇠는 2[0-4]d|25[0-5]|[01]?dd?를 이해하는 것입니다. 여기서 자세히 설명하지는 않겠습니다. 스스로 할 수 있다. 그 의미를 분석한다.
Antonym
때로는 단순 정의된 문자 클래스에 속하지 않는 문자를 찾아야 하는 경우가 있습니다. 예를 들어 숫자 이외의 문자를 찾으려면 반의어를 사용해야 합니다.
예: S+는 공백 문자열과 일치하지 않습니다.
]+> 꺾쇠 괄호로 묶인 문자열로 시작하는 문자열과 일치합니다.
Backreference
괄호를 사용하여 하위 표현식을 지정한 후 이 하위 표현식과 일치하는 텍스트(즉, 이 그룹에서 캡처한 콘텐츠)가 표현식에 있거나 추가 처리를 위해 포함될 수 있습니다. 다른 프로그램에서는. 기본적으로 각 그룹에는 자동으로 그룹 번호가 있습니다. 규칙은 다음과 같습니다. 왼쪽에서 오른쪽으로, 그룹의 왼쪽 괄호를 표시로 사용하여 첫 번째 나타나는 그룹의 그룹 번호는 1, 두 번째 나타나는 그룹의 그룹 번호는 2입니다. 등등.
역참조는 이전 그룹과 일치하는 텍스트를 반복적으로 검색하는 데 사용됩니다. 예를 들어 1은 그룹 1과 일치하는 텍스트를 나타냅니다. 이해하기 어렵나요? 예를 참조하세요.
b(w+)bs+1b는 go go 또는 kitty kitty와 같이 반복되는 단어를 찾는 데 사용할 수 있습니다. 이 표현은 먼저 단어, 즉 단어의 시작과 끝 사이에 두 개 이상의 문자 또는 숫자(b(w+)b)가 포함됩니다. 이 단어는 1번 그룹에 캡처되고 그 다음에는 1개 이상의 공백이 포함됩니다. 문자(s+), 마지막으로 그룹 1에 캡처된 콘텐츠(즉, 이전에 일치하는 단어)(1)입니다.
하위 표현식의 그룹 이름을 직접 지정할 수도 있습니다. 하위 표현식의 그룹 이름을 지정하려면 다음 구문을 사용하십시오: (?
괄호를 사용할 때 특수 용도의 구문이 많이 있습니다. 가장 일반적으로 사용되는 것 중 일부는 다음과 같습니다. 일부 내용 앞이나 뒤(그러나 이러한 내용은 포함하지 않음), 즉 b, ^, $와 같은 위치를 지정하는 데 사용됩니다. 이 위치는 특정 조건을 충족해야 합니다. (즉, 어설션)이므로 너비가 0인 경우 Assert라고도 합니다. 예시를 사용하여 설명하는 것이 가장 좋습니다.
(?=exp)는 폭이 0인 긍정적 예측 예측 어설션이라고도 하며 exp가 나타나는 위치 이후에 표현식이 일치할 수 있음을 나타냅니다. . 예를 들어, bw+(?=ingb)는 ing(ing 제외)으로 끝나는 단어의 앞부분과 일치합니다. 예를 들어 I'm sing while you're dance.를 검색하면 sing 및 dance와 일치합니다.
(?긴 숫자(물론 오른쪽부터 추가)에서 세 자리마다 쉼표를 추가하고 싶다면 앞뒤로 쉼표를 추가해야 하는 부분을 이렇게 찾아보면 됩니다. : ((?다음 예에서는 두 가지 어설션을 모두 사용합니다. (?음수 0 너비 어설션앞서 특정 문자가 아니거나 특정 문자 클래스(반의어)에 속하지 않는 문자를 찾는 방법을 언급했습니다. 하지만 특정 문자가 나타나지 않도록 하고 싶지만 일치시키고 싶지 않은 경우에는 어떻게 해야 할까요? 예를 들어, 문자 q가 나타나지만 q 뒤에 문자 u가 없는 단어를 찾고 싶다면 다음을 시도해 볼 수 있습니다:\b\w*q[^u]\w*\b匹配包含后面不是字母u的字母q的单词。但是如果多做测试(或者你思维足够敏锐,直接就观察出来了),你会发现,如果q出现在单词的结尾的话,像Iraq,Benq,这个表达式就会出错。这是因为[^u]总要匹配一个字符,所以如果q是单词的最后一个字符的话,后面的[^u]将会匹配q后面的单词分隔符(可能是空格,或者是句号或其它的什么),后面的\w*\b将会匹配下一个单词,于是\b\w*q[^u]\w*\b就能匹配整个Iraq fighting。负向零宽断言能解决这样的问题,因为它只匹配一个位置,并不消费任何字符。现在,我们可以这样来解决这个问题:\b\w*q(?!u)\w*\b。
零宽度负预测先行断言(?!exp),断言此位置的后面不能匹配表达式exp。例如:\d{3}(?!\d)匹配三位数字,而且这三位数字的后面不能是数字;\b((?!abc)\w)+\b匹配不包含连续字符串abc的单词。
同理,我们可以用(?
一个更复杂的例子:(?).*(?=)匹配不包含属性的简单HTML标签内里的内容。(?)指定了这样的前缀:被尖括号括起来的单词(比如可能是),然后是.*(任意的字符串),最后是一个后缀(?=)。注意后缀里的\/,它用到了前面提过的字符转义;\1则是一个反向引用,引用的正是捕获的第一组,前面的(\w+)匹配的内容,这样如果前缀实际上是的话,后缀就是了。整个表达式匹配的是和之间的内容(再次提醒,不包括前缀和后缀本身)。
注释
小括号的另一种用途是通过语法(?#comment)来包含注释。例如:2[0-4]\d(?#200-249)|25[0-5](?#250-255)|[01]?\d\d?(?#0-199)。
要包含注释的话,最好是启用“忽略模式里的空白符”选项,这样在编写表达式时能任意的添加空格,Tab,换行,而实际使用时这些都将被忽略。启用这个选项后,在#后面到这一行结束的所有文本都将被当成注释忽略掉。例如,我们可以前面的一个表达式写成这样:
(?<= # 断言要匹配的文本的前缀 <(\w+)> # 查找尖括号括起来的字母或数字(即HTML/XML标签) ) # 前缀结束 .* # 匹配任意文本 (?= # 断言要匹配的文本的后缀 <\/\1> # 查找尖括号括起来的内容:前面是一个"/",后面是先前捕获的标签 ) # 后缀结束
贪婪与懒惰
当正则表达式中包含能接受重复的限定符时,通常的行为是(在使整个表达式能得到匹配的前提下)匹配尽可能多的字符。以这个表达式为例:a.*b,它将会匹配最长的以a开始,以b结束的字符串。如果用它来搜索aabab的话,它会匹配整个字符串aabab。这被称为贪婪匹配。
有时,我们更需要懒惰匹配,也就是匹配尽可能少的字符。前面给出的限定符都可以被转化为懒惰匹配模式,只要在它后面加上一个问号?。这样.*?就意味着匹配任意数量的重复,但是在能使整个匹配成功的前提下使用最少的重复。现在看看懒惰版的例子吧:
a.*?b匹配最短的,以a开始,以b结束的字符串。如果把它应用于aabab的话,它会匹配aab(第一到第三个字符)和ab(第四到第五个字符)。
处理选项
上面介绍了几个选项如忽略大小写,处理多行等,这些选项能用来改变处理正则表达式的方式。下面是.Net中常用的正则表达式选项:
一个经常被问到的问题是:是不是只能同时使用多行模式和单行模式中的一种?答案是:不是。这两个选项之间没有任何关系,除了它们的名字比较相似(以至于让人感到疑惑)以外。
平衡组/递归匹配
有时我们需要匹配像( 100 * ( 50 + 15 ) )这样的可嵌套的层次性结构,这时简单地使用\(.+\)则只会匹配到最左边的左括号和最右边的右括号之间的内容(这里我们讨论的是贪婪模式,懒惰模式也有下面的问题)。假如原来的字符串里的左括号和右括号出现的次数不相等,比如( 5 / ( 3 + 2 ) ) ),那我们的匹配结果里两者的个数也不会相等。有没有办法在这样的字符串里匹配到最长的,配对的括号之间的内容呢?
为了避免(和\(把你的大脑彻底搞糊涂,我们还是用尖括号代替圆括号吧。现在我们的问题变成了如何把xx
这里需要用到以下的语法构造:
(?'group') 把捕获的内容命名为group,并压入堆栈(Stack)
(?'-group') 从堆栈上弹出最后压入堆栈的名为group的捕获内容,如果堆栈本来为空,则本分组的匹配失败
(?(group)yes|no) 如果堆栈上存在以名为group的捕获内容的话,继续匹配yes部分的表达式,否则继续匹配no部分
(?!) 零宽负向先行断言,由于没有后缀表达式,试图匹配总是失败
我们需要做的是每碰到了左括号,就在压入一个"Open",每碰到一个右括号,就弹出一个,到了最后就看看堆栈是否为空--如果不为空那就证明左括号比右括号多,那匹配就应该失败。正则表达式引擎会进行回溯(放弃最前面或最后面的一些字符),尽量使整个表达式得到匹配。
< #最外层的左括号 [^<>]* #最外层的左括号后面的不是括号的内容 ( ( (?'Open'<) #碰到了左括号,在黑板上写一个"Open" [^<>]* #匹配左括号后面的不是括号的内容 )+ ( (?'-Open'>) #碰到了右括号,擦掉一个"Open" [^<>]* #匹配右括号后面不是括号的内容 )+ )* (?(Open)(?!)) #在遇到最外层的右括号前面,判断黑板上还有没有没擦掉的"Open";如果还有,则匹配失败 > #最外层的右括号
平衡组的一个最常见的应用就是匹配HTML,下面这个例子可以匹配嵌套的
上边已经描述了构造正则表达式的大量元素,但是还有很多没有提到的东西。下面是一些未提到的元素的列表,包含语法和简单的说明。你可以在网上找到更详细的参考资料来学习它们--当你需要用到它们的时候。如果你安装了MSDN Library,你也可以在里面找到.net下正则表达式详细的文档。
위 내용은 정규식 초보자를 위한 30분 튜토리얼의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!