정규식 구문 디자인의 가독성이 열악한 특정한 이유가 있습니까?


160

프로그래머들은 코드의 가독성이 작동하는 짧은 구문의 1- 라이너보다 훨씬 중요하지만 상급 개발자가 어느 정도의 정확성으로 해석해야한다고 동의하는 것처럼 보이지만 이는 정규 표현식이 설계된 방식과 정확히 일치하는 것 같습니다. 이것에 대한 이유가 있었습니까?

우리는 모두 selfDocumentingMethodName()그보다 훨씬 낫다는 데 동의합니다 e(). 왜 정규 표현식에도 적용되지 않아야합니까?

구조적 구성이없는 한 줄 논리의 구문을 디자인하는 것이 아니라고 생각합니다.

var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})(0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;

그리고 이것은 URL을 엄격하게 파싱하지도 않습니다!

대신 기본 예제를 위해 일부 파이프 라인 구조를 구성하고 읽을 수있게 만들 수 있습니다.

string.regex
   .isRange('A-Z' || 'a-z')
   .followedBy('/r');

정규 표현식의 매우 간결한 구문은 가능한 가장 짧은 연산 및 논리 구문 이외의 다른 이점을 제공합니까? 궁극적으로 정규 표현식 구문 디자인의 가독성이 열악한 특정한 기술적 이유가 있습니까?


의견은 긴 토론을위한 것이 아닙니다. 이 대화는 채팅 으로 이동 되었습니다 .
maple_shaft

1
RegexToolbox라는 라이브러리 에서이 가독성 문제를 정확하게 해결하려고했습니다. 지금까지는 C #, Java 및 JavaScript로 포팅되었습니다 ( github.com/markwhitaker/RegexToolbox.CSharp 참조) .
Mark Whitaker

이 문제를 해결하기 위해 많은 시도가 있었지만 문화는 바뀌기 어렵습니다. 구두 표현 에 대한 내 대답은 여기를 참조 하십시오 . 사람들은 가능한 가장 일반적인 도구를 사용합니다.
Parivar Saraff

답변:


178

정규 표현식이 그대로 간결하게 설계되는 데는 한 가지 큰 이유가 있습니다. 코드 작성 언어가 아닌 코드 편집기의 명령으로 사용되도록 설계되었습니다.보다 정확하게 ed는 정규 표현식을 사용하는 최초의 프로그램 중 하나였습니다. 거기에서 정규식이 세계 정복을위한 정복을 시작했습니다. 예를 들어이 ed명령은 g/<regular expression>/p곧라는 별도의 프로그램에 영감을 주었으며 grep오늘날에도 여전히 사용되고 있습니다. 때문에 그들의 힘, 그들은 이후 표준화했고, 같은 다양한 도구에 사용 sed하고vim

그러나 퀴즈에는 충분합니다. 그렇다면 왜이 기원이 간결한 문법을 ​​선호할까요? 한 번 더 읽기 위해 편집기 명령을 입력하지 않기 때문입니다. 그것을 정리하는 방법을 기억할 수 있고,하고 싶은 일을 할 수 있으면 충분합니다. 그러나 입력해야하는 모든 문자는 파일 편집 진행 속도가 느려집니다. 정규 표현식 구문은 비교적 복잡한 검색을 버리기 방식으로 작성하도록 설계되었으므로 프로그램에 대한 입력을 구문 분석하기 위해 코드로 사용하는 두통을 사람들에게 정확히 제공합니다.


5
정규식은 구문 분석하지 않습니다. 그렇지 않으면, stackoverflow.com/questions/1732348/... . 그리고 두통.
njzk2

19
@ njzk2 그 대답은 실제로 잘못되었습니다. HTML 문서 는 일반 언어가 아니라 HTML open tag 입니다. 실제로 질문은 이런 질문입니다.
Random832

11
이것은 원래 정규 표현식이 왜 그렇게 비밀 스러운지를 설명하는 좋은 대답이지만 현재 가독성이 향상된 대체 표준이없는 이유는 설명하지 않습니다.
Doc Brown

13
따라서 grep잘못 발음 된 "잡기"라고 생각하는 사람들에게는 사실 g/ re(정규 표현 용) / p?
Hagen von Eitzen

6
@DannyPflughoeft 아니오, 그렇지 않습니다. 열린 태그는 단지 <aaa bbb="ccc" ddd='eee'>입니다. 태그 안에 중첩 된 태그가 없습니다. 태그를 중첩 할 수 없으며 중첩 된 것은 요소 (열린 태그, 하위 요소를 포함한 내용, 가까운 태그)이며 구문 분석에 대해 질문 하지 않은 태그 입니다. HTML 태그 는 일반적인 언어입니다. 밸런싱 / 네 스팅은 태그 위의 수준에서 발생합니다.
Random832

62

당신이 인용하는 정규 표현식은 끔찍한 혼란이며 누구나 읽을 수 있다고 동의하지는 않습니다. 동시에, 그 추악함의 대부분은 해결되는 문제에 내재되어 있습니다. 여러 계층의 중첩이 있고 URL 문법은 비교적 복잡합니다 (어느 언어로 간결하게 통신하기에는 너무 복잡합니다). 그러나이 정규식이 묘사하는 것을 설명하는 더 좋은 방법이 있다는 것은 사실입니다. 왜 사용하지 않습니까?

큰 이유는 관성과 편재입니다. 처음에는 어떻게 그렇게 인기를 얻었는지는 설명하지 않지만 이제는 정규 표현식을 아는 사람이라면 누구나이 기술을 방언 사이에 거의 차이없이 백 가지 언어와 추가로 수천 개의 소프트웨어 도구 ( 예를 들어, 텍스트 편집기 및 명령 행 도구). 그건 그렇고, 후자는 프로그래머가 아닌 사람들이 많이 사용하기 때문에 프로그램 작성에 해당하는 솔루션을 사용할 수 없으며 사용할 수 없었습니다 .

그럼에도 불구하고 정규 표현식은 종종 과도하게 사용됩니다. 즉 다른 도구가 훨씬 더 나은 경우에도 적용됩니다. 정규식 구문이 끔찍 하다고 생각하지 않습니다 . 그러나 그것은 짧고 간단한 패턴에서 훨씬 더 낫습니다. C와 같은 언어로 된 식별자의 전형적인 예는 [a-zA-Z_][a-zA-Z0-9_]*최소한의 정규식 지식으로 읽을 수 있으며 일단 그 막대가 충족되면 분명하고 간결합니다. 더 적은 문자를 요구하는 것은 본질적으로 나쁘지 않습니다. 간결한 것은 당신이 이해할 수 있다면 미덕입니다.

이 구문이 다음과 같은 간단한 패턴에서 탁월한 이유는 두 가지가 있습니다. 대부분의 문자를 이스케이프 할 필요가 없으므로 비교적 자연스럽게 읽으며 사용 가능한 모든 구두점을 사용하여 다양한 간단한 구문 분석 조합기를 표현합니다. 아마도 가장 중요한 것은 시퀀싱을 위해 아무것도 필요하지 않습니다 . 첫 번째를 쓴 다음에 나오는 것을 쓰십시오. 당신의 명암이 followedBy다음과 같은 패턴은 특히, 하지 리터럴하지만 더 복잡한 식입니다.

왜 더 복잡한 경우에 부족합니까? 세 가지 주요 문제가 있습니다.

  1. 추상화 기능이 없습니다. 정규식과 같은 이론적 컴퓨터 과학 분야에서 유래 한 공식 문법에는 일련의 제작물이 있으므로 패턴의 중간 부분에 이름을 지정할 수 있습니다.

    # This is not equivalent to the regex in the question
    # It's just a mock-up of what a grammar could look like
    url      ::= protocol? '/'? '/'? '/'? (domain_part '.')+ tld
    protocol ::= letter+ ':'
    ...
    
  2. 위에서 볼 수 있듯이 특별한 의미가없는 공백은 눈에 편한 서식을 허용하는 데 유용합니다. 코멘트와 같은 것. 공백은 리터럴이기 때문에 정규 표현식은 그렇게 할 수 없습니다 ' '. 참고 : 일부 구현에서는 공백이 무시되고 주석이 가능한 "verbose"모드가 허용됩니다.

  3. 일반적인 패턴과 결합자를 설명하는 메타 언어는 없습니다. 예를 들어, digit규칙을 한 번 작성하여 컨텍스트 프리 문법에서 계속 사용할 수는 있지만, "함수"를 정의하여 프로덕션이 주어지고 p추가로 무언가를하는 새로운 프로덕션을 작성하는 것은 불가능합니다. 쉼표로 구분 된 발생 목록을 생성합니다 p.

당신이 제안하는 접근법은 분명히 이러한 문제를 해결합니다. 그것은 필요한 것보다 훨씬 더 간결하게 거래되기 때문에 그것들을 잘 풀지 못합니다. 처음 두 가지 문제는 비교적 간단하고 간결한 도메인 별 언어로 유지하면서 해결할 수 있습니다. 세번째는 ... 프로그래밍 솔루션에는 범용 프로그래밍 언어가 필요하지만 제 경험상 세 번째는 그 중 가장 적은 문제입니다. 프로그래머가 새로운 콤비 네이터를 정의하는 능력에 대해 그리워하는 동일한 복잡한 작업이 충분히 발생하는 패턴은 거의 없습니다. 그리고 이것이 필요할 때, 어쨌든 정규 표현식으로 구문 분석 할 수없고 해석해서는 안될 정도로 언어가 복잡합니다.

이러한 경우에 대한 솔루션이 존재합니다. 약 10 만개의 파서 결합기 라이브러리가 있으며, 다른 연산 세트, 종종 다른 구문, 거의 항상 정규 표현식보다 구문 분석 능력이 더 높습니다 (즉, 문맥이없는 언어 또는 일부 크기 조정 가능). 그 하위 집합). 그런 다음 위에 설명 된 "더 나은 DSL 사용"접근 방식을 사용하는 파서 생성기가 있습니다. 그리고 적절한 코드로 파싱을 직접 작성하는 옵션이 항상 있습니다. 간단한 하위 작업에 정규식을 사용하고 정규 표현식을 호출하는 코드에서 복잡한 작업을 수행하여 혼합하여 일치시킬 수도 있습니다.

정규 표현식이 어떻게 인기를 얻었는지 설명 할 수있는 컴퓨팅 초기에 대해서는 잘 모릅니다. 그러나 그들은 여기에 있습니다. 현명하게 사용해야하며 현명 할 때는 사용 하지 마십시오.


9
I don't know enough about the early years of computing to explain how regular expressions came to be so popular.기본 정규식 엔진은 구현하기가 쉽고 컨텍스트가없는 효율적인 파서보다 훨씬 쉽습니다.
biziclop

15
@biziclop 나는이 변수를 과대 평가하지 않을 것입니다. " 다른 컴파일러 컴파일러" 라고 불릴만큼 충분한 선행 작업이있는 Yacc 는 70 년대 초에 만들어졌으며 이전 버전 grep(버전 3과 버전 4)의 Unix에 포함되었습니다 . 정규 표현식의 첫 번째 주요 사용은 1968 년이었습니다.

나는 Wikipedia에서 찾은 것을 계속 할 수 있지만 (100 %는 믿지 않을 것입니다), yacc1975 년 LALR 파서 (실제로 사용 가능한 파서의 첫 번째 클래스 중 하나)에 대한 아이디어가 만들어졌습니다. JIT가 식 (!)을 컴파일 한 최초의 정규식 엔진 구현 (1968)이 1968 년에 출판되었습니다. 그러나 당신이 옳은 말을하기는 어렵습니다. 떨어져서". 그러나 일단 개발자가 사용하는 텍스트 편집기에 넣은 후에도 자신의 소프트웨어에서도 사용하고 싶었습니다.
biziclop

1
@ jpmc26 는 정규 표현식 장에 JavaScript The Good Parts 라는 책을 열었습니다 .
Viziionary

2
with very few differences between dialects나는 그것이 "매우 적다"고 말하지 않을 것입니다. 사전 정의 된 문자 클래스에는 서로 다른 방언간에 여러 가지 정의가 있습니다. 또한 각 방언마다 고유 한 구문 분석 문제가 있습니다.
nhahtdh

39

역사적 관점

Wikipedia 기사 는 정규 표현식의 기원에 대해 매우 상세합니다 (Kleene, 1956). 원래 구문은 비교적 간단했다 *, +, ?, |및 그룹화 (...). 그것은 (간결했다 형식 언어가 간결 수학 표기법으로 표현하는 경향이 있기 때문에, 두 사람은 반드시 반대하지 않습니다, 읽기).

나중에, 구문과 기능은 편집자들과 함께 발전하고 Perl 과 함께 자랐습니다. Perl 은 디자인에 의해 간결 해 지려고했습니다 ( "공통 구성은 짧아야합니다" ). 이것은 구문을 많이 복잡하게 만들었지 만, 사람들은 이제 정규 표현식에 익숙해 져 있고 (읽지 않을 경우) 잘 작성합니다. 때로는 쓰기 전용이라는 사실은 너무 길면 일반적으로 올바른 도구가 아니라는 것을 나타냅니다. 정규 표현식은 악용 될 때 읽을 수없는 경향이 있습니다.

문자열 기반 정규 표현식을 넘어

다른 구문에 대해 말하기, 이제 (이미 존재 하나 살펴 보자 CL-ppcre 에서, 커먼 리스프를 ). 긴 정규 표현식은 ppcre:parse-string다음과 같이 구문 분석 할 수 있습니다 .

(let ((*print-case* :downcase)
      (*print-right-margin* 50))
  (pprint
   (ppcre:parse-string "^(?:([A-Za-z]+):)?(\\/{0,3})(0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$")))

... 결과는 다음과 같습니다.

(:sequence :start-anchor
 (:greedy-repetition 0 1
  (:group
   (:sequence
    (:register
     (:greedy-repetition 1 nil
      (:char-class (:range #\A #\Z)
       (:range #\a #\z))))
    #\:)))
 (:register (:greedy-repetition 0 3 #\/))
 (:register
  (:sequence "0-9" :everything "-A-Za-z"
   (:greedy-repetition 1 nil #\])))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\:
    (:register
     (:greedy-repetition 1 nil :digit-class)))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\/
    (:register
     (:greedy-repetition 0 nil
      (:inverted-char-class #\? #\#))))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\?
    (:register
     (:greedy-repetition 0 nil
      (:inverted-char-class #\#))))))
 (:greedy-repetition 0 1
  (:group
   (:sequence #\#
    (:register
     (:greedy-repetition 0 nil :everything)))))
 :end-anchor)

이 구문은 더 장황하며 아래 주석을 보면 더 읽기 쉬운 것은 아닙니다. 따라서 구문이 덜 간결하기 때문에 상황이 자동으로 명확해질 것이라고 가정하지 마십시오 .

그러나 정규식에 문제가 발생하면이 형식으로 변환하면 코드를 해독하고 디버그하는 데 도움이 될 수 있습니다. 이는 단일 문자 오류를 발견하기 어려운 문자열 기반 형식에 비해 한 가지 장점입니다. 이 구문 의 주요 장점 은 문자열 기반 인코딩 대신 구조적 형식을 사용하여 정규식을 조작하는 것입니다. 이를 통해 프로그램의 다른 데이터 구조와 같은 표현식 을 작성 하고 작성할 수 있습니다. 위의 구문을 사용하면 일반적으로 작은 부분에서 표현식을 작성하려고하기 때문입니다 ( CodeGolf 답변 참조 ). 예를 들어, 1을 쓸 수 있습니다 .

`(:sequence
   :start-anchor
   ,(protocol)
   ,(slashes)
   ,(domain)
   ,(top-level-domain) ... )

문자열 연결 및 도우미 함수로 래핑 된 보간을 사용하여 문자열 기반 정규식을 구성 할 수도 있습니다. 그러나 코드복잡 하게 만드는 문자열 조작에는 제한 이 있습니다 ( $(...)배시의 백틱과 달리 중첩 문제에 대해 생각하십시오 . 또한 이스케이프 문자는 두통을 유발할 수 있습니다).

또한 위의 형식은 형식을 허용 (:regex "string")하므로 간결한 표기법을 나무와 혼합 할 수 있습니다. 이 모든 것이 IMHO가 가독성과 구성 성을 좋게 만듭니다. 이 주소 delnan에 의해 표현 된 세 가지 문제 간접적으로 (즉,하지 정규 표현식 자체의 언어).

결론적으로

  • 대부분의 경우 간결한 표기법을 읽을 수 있습니다. 역 추적 등을 포함하는 확장 표기법을 다루는 데 어려움이 있지만, 그 사용이 거의 정당화되지 않습니다. 정규 표현식을 부적절하게 사용하면 읽을 수없는 표현식이 생길 수 있습니다.

  • 정규식은 문자열로 인코딩 할 필요가 없습니다. 정규식을 작성하고 작성하는 데 도움이되는 라이브러리 나 도구가있는 경우 문자열 조작과 관련된 많은 잠재적 인 버그를 피할 수 있습니다.

  • 대안 적으로, 공식 문법은 더 읽기 쉽고 하위 표현식의 이름을 지정하고 추상화하는 데 더 좋습니다. 터미널은 일반적으로 간단한 정규식으로 표현됩니다.


1. 정규식은 응용 프로그램에서 상수 인 경향이 있으므로 읽기시 식을 작성하는 것이 좋습니다. 참조 create-scannerload-time-value:

'(:sequence :start-anchor #.(protocol) #.(slashes) ... )

5
어쩌면 나는 전통적인 RegEx 구문에 익숙했지만 22 개의 읽기 쉬운 줄이 동등한 한 줄 정규 표현식보다 이해하기 쉽다고 확신하지 못합니다.

3
당신이 정말로 긴 정규식을해야하는 경우 @ dan1111 "어느 정도 읽을 수있는";-) 좋아하지만, 그것은 같은 하위 집합을 정의하는 의미가 있습니다 digits, ident그리고 그것들을 구성합니다. 그들은 내가 본 것처럼 일반적으로 문자열 조작 (연결 또는 보간)을 사용하여 올바른 이스케이프와 같은 다른 문제를 일으 킵니다. \\\\`예를 들어 emacs 패키지에서 발생하는 항목을 검색하십시오 . 같은 이스케이프 문자 같은 특수 문자를 모두 사용되기 때문에, BTW이 악화되어 \n\"정규식 구문 \(. 좋은 구문의 비 혀짤배기 예는 printf어디 %d와 충돌하지 않습니다 \d.
coredump

1
정의 된 부분 집합에 대한 공정 점. 그것은 많은 의미가 있습니다. 자세한 정보가 개선되었다는 것에 회의적입니다. 초보자에게는 더 쉬울 수 있습니다 (같은 개념 greedy-repetition은 직관적이지 않고 학습해야합니다). 그러나 전체 패턴을보고 파악하기가 훨씬 어렵 기 때문에 전문가의 유용성을 희생합니다.

@ dan1111 나는 그 자체만으로는 그 자체가 개선이 아니라는 것에 동의합니다. 개선 될 수있는 것은 문자열 대신 구조적 데이터를 사용하여 정규식을 조작하는 것입니다.
coredump

@ dan1111 아마도 Haskell을 사용하여 편집을 제안해야합니까? 파섹은 단지 9 줄로한다. 단일 라이너로 : do {optional (many1 (letter) >> char ':'); choice (map string ["///","//","/",""]); many1 (oneOf "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-."); optional (char ':' >> many1 digit); optional (char '/' >> many (noneOf "?#")); optional (char '?' >> many (noneOf "#")); optional (char '#' >> many (noneOf "\n")); eof}. 로 긴 문자열을 지정하는 등의 몇 줄 domainChars = ...section start p = optional (char start >> many p)는 아주 간단 보인다.
CR Drost

25

정규 표현식의 가장 큰 문제는 지나치게 간결한 구문이 아니라 복잡한 빌딩 블록에서 작성하는 대신 단일 표현식으로 복잡한 정의를 표현하려고한다는 것입니다. 이것은 변수와 함수를 사용하지 않고 코드를 한 줄에 모두 포함시키는 프로그래밍과 유사합니다.

정규식을 BNF 와 비교하십시오 . 문법은 정규식보다 훨씬 깨끗하지는 않지만 다르게 사용됩니다. 간단한 명명 된 기호를 정의하여 시작하여 일치시키려는 전체 패턴을 설명하는 기호에 도달 할 때까지 구성하십시오.

예를 들어 rfc3986 의 URI 구문을 살펴보십시오 .

URI           = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
scheme        = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
hier-part     = "//" authority path-abempty
              / path-absolute
              / path-rootless
              / path-empty
...

명명 된 하위 표현식 포함을 지원하는 정규식 구문의 변형을 사용하여 거의 동일한 내용을 작성할 수 있습니다.


개인적으로 나는 문자 클래스, 연결, 선택 또는 반복과 같이 일반적으로 사용되는 기능에는 구문과 같은 간결한 정규 표현식이 적합하다고 생각하지만 미리보기 이름과 같은 더 복잡하고 희귀 한 기능이 바람직합니다. 일반 프로그래밍에서 +또는 *일반 프로그래밍에서 연산자를 사용 하고 드문 작업을 위해 명명 된 함수로 전환 하는 방법과 매우 유사 합니다.


12

selfDocumentingMethodName ()이 e ()보다 훨씬 낫다

그렇습니까? 대부분의 언어가 BEGIN 및 END가 아닌 블록 구분 기호로 {및}를 갖는 이유가 있습니다.

간결함을 좋아하는 사람들은 일단 구문을 알고 있으면 단기 용어가 더 좋습니다. d (숫자)가 '숫자'인 경우 정규식 예제를 읽는 것이 더 무섭다고 상상해보십시오. 제어 문자로보다 쉽게 ​​구문 분석 할 수있게하면 XML처럼 보입니다. 구문을 알고 나면 좋지 않습니다.

질문에 올바르게 대답하려면 정규 표현식이 간결한 것이 필수였던 시절부터 시작해야한다는 것을 알아야합니다. 오늘날 1MB XML 문서는 큰 문제가 아니라고 생각하기 쉽지만 1MB가 꽤 컸던 날에 대해 이야기하고 있습니다. 전체 저장 용량. 당시에는 사용되는 언어가 더 적었고 정규 표현식이 펄이나 C에서 백만 마일 떨어져 있지 않으므로 구문은 배우는 것에 만족하는 오늘날 프로그래머에게 친숙 할 것입니다. 그래서 더 장황하게 할 이유가 없었습니다.


1
selfDocumentingMethodName있다 일반적으로 합의 보다 더 나은 것으로 e프로그래머의 직관과 일치하지 않기 때문에 실제로 가독성이나 좋은 품질의 코드를 구성하는 것에 측면에서 현실 . 합의를하는 사람들은 틀렸지 만 그렇게 된 것입니다.
Leushenko

1
@ Leushenko : 당신 e()은 그보다 낫다고 주장하고 selfDocumentingMethodName()있습니까?
JacquesB 2009 년

3
@JacquesB는 전역 이름과 같은 모든 컨텍스트에 해당되지 않을 수 있습니다. 그러나 엄밀한 범위의 것? 거의 확실합니다. 기존의 지혜보다 훨씬 더 자주.
Leushenko

1
@ Leushenko : 문맥이 단일 문자 기능 이름이 더 설명적인 이름보다 낫다는 것을 상상하기가 어렵습니다. 그러나 나는 이것이 순수한 의견이라고 생각합니다.
JacquesB

1
@MilesRout : 예제는 실제로 e()자체 문서화 방법 이름입니다. 설명적인 메소드 이름 대신 단일 문자 메소드 이름을 사용하는 것이 어떤 컨텍스트에서 개선되었는지 설명 할 수 있습니까?
JacquesB

6

정규식은 레고 조각과 같습니다. 언뜻 보면 서로 다른 모양의 플라스틱 부품을 결합 할 수 있습니다. 당신은 당신이 형성 할 수있는 가능한 많은 다른 것들이 없을 것이라고 생각할 수도 있지만 다른 사람들이하는 놀라운 일을보고 놀라운 장난감인지 궁금합니다.

정규식은 레고 조각과 같습니다. 사용할 수있는 인수는 거의 없지만 여러 가지 형식으로 연결하면 수많은 복잡한 작업에 사용할 수있는 수백만 개의 다른 정규식 패턴이 형성됩니다.

사람들은 정규 표현식 매개 변수를 거의 사용하지 않았습니다. 많은 언어는 문자열의 길이를 확인하거나 숫자 부분을 분리하는 기능을 제공합니다. 문자열 함수를 사용하여 텍스트를 슬라이스하고 재구성 할 수 있습니다. 복잡한 형식을 사용하여 매우 복잡한 작업을 수행 할 때 정규식의 힘을 알 수 있습니다.

SO에서 수만 개의 정규식 질문을 찾을 수 있으며 중복으로 표시되는 경우는 거의 없습니다. 이것만으로도 서로 매우 다른 가능한 고유 한 유스 케이스를 보여줍니다.

그리고 이처럼 다양한 고유 한 작업을 처리하기 위해 미리 정의 된 방법을 제공하는 것은 쉽지 않습니다. 이러한 종류의 작업에 문자열 함수가 있지만 해당 기능이 지정 작업에 충분하지 않으면 정규식을 사용할 때입니다.


2

나는 이것이 힘보다는 실천의 문제라는 것을 알고있다. 일반적으로 복합 특성을 가정하는 대신 정규식을 직접 구현할 때 문제가 발생합니다 . 마찬가지로 좋은 프로그래머는 자신의 프로그램 기능을 간결한 방법으로 분해합니다.

예를 들어 URL의 정규식 문자열은 대략 다음과 같이 줄어들 수 있습니다.

UriRe = [scheme][hier-part][query][fragment]

에:

UriRe = UriSchemeRe + UriHierRe + "(/?|/" + UriQueryRe + UriFragRe + ")"
UriSchemeRe = [scheme]
UriHierRe = [hier-part]
UriQueryRe = [query]
UriFragRe = [fragment]

규칙적인 표현은 근사한 것이지만, 복잡해 보이는 사람들에 의해 학대당하는 경향이 있습니다. 결과 표현은 장기적인 가치가없는 수사적이다.


2
불행히도 대부분의 프로그래밍 언어에는 정규 표현식 작성에 도움이되는 기능이 포함되어 있지 않으며 그룹 캡처 작업 방식도 구성에 매우 친숙하지 않습니다.
코드 InChaos

1
다른 언어는 "perl 호환 정규식"지원에서 Perl 5를 따라야합니다. 하위 표현식은 단순히 정규식 사양의 문자열을 연결하는 것과 다릅니다. 암시 적 번호 매기기에 의존하지 않고 캡처 이름을 지정해야합니다.
JDługosz

0

@cmaster가 말했듯이 정규 표현식은 원래 즉시 사용하도록 설계되었으며 라인 노이즈 구문이 여전히 가장 인기있는 것은 기괴합니다 (약간 우울합니다). 내가 생각할 수있는 유일한 설명은 관성, 마조히즘 또는 마치 모와 관련이 있습니다 ( '관성'이 무언가를하는 가장 매력적인 이유는 아닙니다 ...)

Perl은 공백과 주석을 허용하여 읽기 쉽게하기 위해 다소 약한 시도를하지만 원격으로 상상할 수있는 일은하지 않습니다.

다른 구문이 있습니다. 좋은 예는 regexpsscsh 구문입니다 . 제 경험상 입력하기 쉽지만 사실 후에도 읽을 수 있는 regexp를 생성합니다.

[ scsh 는 다른 이유로 훌륭합니다. 그중 하나가 유명한 승인 텍스트입니다 ]


2
Perl6는 그렇습니다! 문법을보세요.
JDługosz

@ JDługosz 아시다시피, 정규 표현식의 대체 구문보다는 파서 생성기의 메커니즘과 비슷합니다. 그러나 구별은 아마도 깊은 것이 아닙니다.
Norman Grey

대체물 일 수 있지만 동일한 힘으로 제한되지는 않습니다. regedp를 수정 자와 일치하는 1 대 1의 구문을 사용하여보다 읽기 쉬운 구문으로 인라인 문법으로 변환 할 수 있습니다. 이를 홍보하는 예는 원래 Perl Apocalypse에 있습니다.
JDługosz

0

나는 정규 표현식이 가능한 한 '일반적'이고 단순하도록 설계되었으므로 어디에서나 (거의) 같은 방식으로 사용할 수 있다고 생각합니다.

예를 들어 regex.isRange(..).followedBy(..)특정 프로그래밍 언어의 구문과 객체 지향 스타일 (메소드 체인)에 모두 연결되어 있습니다.

예를 들어 C 에서이 정확한 '정규식'은 어떻게 보입니까? 코드를 변경해야합니다.

가장 '일반적인'접근 방식은 간단한 간결한 언어를 정의하여 변경없이 다른 언어로 쉽게 포함시킬 수 있습니다. 그리고 그것은 (거의) 정규식입니다.


0

Perl 호환 정규 표현식 엔진이 널리 사용되므로 많은 편집자와 언어가 이해하는 간결한 정규 표현식 구문을 제공합니다. @ JDługosz가 의견에서 지적했듯이 Perl 6 (Perl 5의 새로운 버전뿐만 아니라 완전히 다른 언어)은 개별적으로 정의 된 요소에서 정규 표현식을 작성하여 더 읽기 쉽게 만들려고했습니다. 예를 들어, 다음은 Wikibooks에서 URL을 구문 분석하는 예제 문법입니다 .

grammar URL {
  rule TOP {
    <protocol>'://'<address>
  }
  token protocol {
    'http'|'https'|'ftp'|'file'
  }
  rule address {
    <subdomain>'.'<domain>'.'<tld>
  }
  ...
}

이와 같이 정규 표현식을 분할하면 각 비트를 개별적으로 정의 domain하거나 (예 : 영숫자로 제한 ) 서브 클래 싱을 통해 확장 할 수 있습니다 (예 : 제약 FileURL is URL조건 protocol"file").

따라서 : 정규 표현식의 간결함에 대한 기술적 이유는 없지만,이를 표현하는 더 새롭고 더 깨끗하고 읽기 쉬운 방법이 이미 있습니다! 이 분야에서 새로운 아이디어가 나오기를 바랍니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.