programing

자바스크립트에서 긴 정규식을 여러 줄로 분할하는 방법은 무엇입니까?

instargram 2023. 8. 20. 10:15
반응형

자바스크립트에서 긴 정규식을 여러 줄로 분할하는 방법은 무엇입니까?

저는 매우 긴 정규 표현식을 가지고 있는데, JSLint 규칙에 따라 각 줄의 길이를 80자로 유지하기 위해 자바스크립트 코드에서 여러 줄로 나누고 싶습니다.그냥 읽기에 더 좋은 것 같아요.다음은 패턴 샘플입니다.

var pattern = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;

@KuiInc 응답을 확장하면 모든 특수 문자를 수동으로 이스케이프하는 것을 피할 수 있습니다.sourceRegExp물건.

예:

var urlRegex = new RegExp(
  /(?:(?:(https?|ftp):)?\/\/)/.source       // protocol
  + /(?:([^:\n\r]+):([^@\n\r]+)@)?/.source  // user:pass
  + /(?:(?:www.)?([^/\n\r]+))/.source       // domain
  + /(\/[^?\n\r]+)?/.source                 // request
  + /(\?[^#\n\r]*)?/.source                 // query
  + /(#?[^\n\r]*)?/.source                  // anchor
);

또는 반복하지 않으려면.source은 성을사수수있습다니행할을 하여 할 수 .Array.map()함수:

var urlRegex = new RegExp([
  /(?:(?:(https?|ftp):)?\/\/)/,     // protocol
  /(?:([^:\n\r]+):([^@\n\r]+)@)?/,  // user:pass
  /(?:(?:www.)?([^/\n\r]+))/,       // domain
  /(\/[^?\n\r]+)?/,                 // request
  /(\?[^#\n\r]*)?/,                 // query
  /(#?[^\n\r]*)?/,                  // anchor
].map(function (r) { return r.source; }).join(''));

다음과 같이 수 ..map(r => r.source).

[편집 2022/08] 작은 github 저장소를 생성하여 공간, 주석 및 템플릿으로 정규 표현을 생성하였습니다.


문자열로 변환하고 다음을 호출하여 식을 만들 수 있습니다.new RegExp():

var myRE = new RegExp (['^(([^<>()[\]\\.,;:\\s@\"]+(\\.[^<>(),[\]\\.,;:\\s@\"]+)*)',
                        '|(\\".+\\"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.',
                        '[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\\.)+',
                        '[a-zA-Z]{2,}))$'].join(''));

주의:

  1. 표현식 리터럴을 문자열로 변환할 때 문자열 리터럴을 평가할 때 백슬래시가 사용되므로 모든 백슬래시를 피해야 합니다.(자세한 내용은 카요의 코멘트를 참조하십시오.

  2. RegExp를 두 변수로 할 수 있습니다.

    /regex/g=>new RegExp('regex', 'g')

[추가 ES20xx(태그 부착 템플릿)]

ES20xx에서는 태그가 지정된 템플릿을 사용할 수 있습니다.스니펫을 참조하십시오.

참고:

  • 여기서 단점은 정규식 문자열에 일반 공백을 사용할 수 없다는 것입니다(항상 사용).\s,\s+,\s{1,x},\t,\n

(() => {
  const createRegExp = (str, opts) => 
    new RegExp(str.raw[0].replace(/\s/gm, ""), opts || "");
  const yourRE = createRegExp`
    ^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|
    (\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|
    (([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$`;
  console.log(yourRE);
  const anotherLongRE = createRegExp`
    (\byyyy\b)|(\bm\b)|(\bd\b)|(\bh\b)|(\bmi\b)|(\bs\b)|(\bms\b)|
    (\bwd\b)|(\bmm\b)|(\bdd\b)|(\bhh\b)|(\bMI\b)|(\bS\b)|(\bMS\b)|
    (\bM\b)|(\bMM\b)|(\bdow\b)|(\bDOW\b)
    ${"gi"}`;
  console.log(anotherLongRE);
})();

에서 문자열 new RegExp백슬래시를 모두 피해야 하기 때문에 어색합니다.더 작은 정규식을 작성하고 연결할 수 있습니다.

이 정규식을 나누자.

/^foo(.*)\bar$/

우리는 나중에 사물을 더 아름답게 만드는 기능을 사용할 것입니다.

function multilineRegExp(regs, options) {
    return new RegExp(regs.map(
        function(reg){ return reg.source; }
    ).join(''), options);
}

그리고 이제 락하자꾸나

var r = multilineRegExp([
     /^foo/,  // we can add comments too
     /(.*)/,
     /\bar$/
]);

비용이 들기 때문에 한 번만 진짜 정규식을 만들고 그것을 사용해 보세요.

템플릿 리터럴의 놀라운 세계 덕분에 이제 ES6에서 크고, 다중 줄이며, 주석이 잘 달린, 의미론적으로 중첩된 정규식을 작성할 수 있습니다.

//build regexes without worrying about
// - double-backslashing
// - adding whitespace for readability
// - adding in comments
let clean = (piece) => (piece
    .replace(/((^|\n)(?:[^\/\\]|\/[^*\/]|\\.)*?)\s*\/\*(?:[^*]|\*[^\/])*(\*\/|)/g, '$1')
    .replace(/((^|\n)(?:[^\/\\]|\/[^\/]|\\.)*?)\s*\/\/[^\n]*/g, '$1')
    .replace(/\n\s*/g, '')
);
window.regex = ({raw}, ...interpolations) => (
    new RegExp(interpolations.reduce(
        (regex, insert, index) => (regex + insert + clean(raw[index + 1])),
        clean(raw[0])
    ))
);

이를 사용하여 다음과 같은 정규식을 작성할 수 있습니다.

let re = regex`I'm a special regex{3} //with a comment!`;

출력

/I'm a special regex{3}/

아니면 다중 회선은 어떨까요?

'123hello'
    .match(regex`
        //so this is a regex

        //here I am matching some numbers
        (\d+)

        //Oh! See how I didn't need to double backslash that \d?
        ([a-z]{1,3}) /*note to self, this is group #2*/
    `)
    [2]

hel 끔깔!!
" 내가 실제로 새로운 줄을 ?", "만약내실가새검한다면야색해라?", "음, 다사용다니합음그런제로인?"를 사용하세요\n 바보야!
파이어폭스와 크롬으로 작업 중입니다.


좋아요, "좀 더 복잡한 건 어때요?"
예, 여기 제가 작업하던 JS 파서를 파괴하는 물체의 일부가 있습니다.

regex`^\s*
    (
        //closing the object
        (\})|

        //starting from open or comma you can...
        (?:[,{]\s*)(?:
            //have a rest operator
            (\.\.\.)
            |
            //have a property key
            (
                //a non-negative integer
                \b\d+\b
                |
                //any unencapsulated string of the following
                \b[A-Za-z$_][\w$]*\b
                |
                //a quoted string
                //this is #5!
                ("|')(?:
                    //that contains any non-escape, non-quote character
                    (?!\5|\\).
                    |
                    //or any escape sequence
                    (?:\\.)
                //finished by the quote
                )*\5
            )
            //after a property key, we can go inside
            \s*(:|)
      |
      \s*(?={)
        )
    )
    ((?:
        //after closing we expect either
        // - the parent's comma/close,
        // - or the end of the string
        \s*(?:[,}\]=]|$)
        |
        //after the rest operator we expect the close
        \s*\}
        |
        //after diving into a key we expect that object to open
        \s*[{[:]
        |
        //otherwise we saw only a key, we now expect a comma or close
        \s*[,}{]
    ).*)
$`

을 합니다./^\s*((\})|(?:[,{]\s*)(?:(\.\.\.)|(\b\d+\b|\b[A-Za-z$_][\w$]*\b|("|')(?:(?!\5|\\).|(?:\\.))*\5)\s*(:|)|\s*(?={)))((?:\s*(?:[,}\]=]|$)|\s*\}|\s*[{[:]|\s*[,}{]).*)$/

그리고 작은 데모로 그것을 실행하는 것입니까?

let input = '{why, hello, there, "you   huge \\"", 17, {big,smelly}}';
for (
    let parsed;
    parsed = input.match(r);
    input = parsed[parsed.length - 1]
) console.log(parsed[1]);

성공적으로 출력

{why
, hello
, there
, "you   huge \""
, 17
,
{big
,smelly
}
}

따옴표로 묶은 문자열이 성공적으로 캡처되었습니다.
크롬과 파이어폭스에서 테스트해봤는데, 아주 잘 작동합니다!

궁금하다면 제가 무엇을 하고 있었는지, 그리고 그것의 시연을 확인할 수 있습니다.
파이어폭스는 역참조나 명명된 그룹을 지원하지 않기 때문에 Chrome에서만 작동합니다.따라서 이 답변에 제시된 예는 실제로 중성화된 버전이므로 잘못된 문자열을 쉽게 받아들이도록 속을 수 있습니다.

여기에 좋은 답이 있지만, 완성도를 위해서는 자바스크립트의 핵심 기능인 프로토타입 체인 상속을 언급해야 합니다.다음과 같은 것이 아이디어를 설명합니다.

RegExp.prototype.append = function(re) {
  return new RegExp(this.source + re.source, this.flags);
};

let regex = /[a-z]/g
.append(/[A-Z]/)
.append(/[0-9]/);

console.log(regex); //=> /[a-z][A-Z][0-9]/g

위 정규식에 제대로 작동하지 않는 검은색 슬래시가 있습니다.그래서 정규식을 편집했습니다.이메일 유효성 확인을 위해 99.99% 작동하는 정규식을 고려하십시오.

let EMAIL_REGEXP = 
new RegExp (['^(([^<>()[\\]\\\.,;:\\s@\"]+(\\.[^<>()\\[\\]\\\.,;:\\s@\"]+)*)',
                    '|(".+"))@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.',
                    '[0-9]{1,3}\])|(([a-zA-Z\\-0-9]+\\.)+',
                    '[a-zA-Z]{2,}))$'].join(''));

과 같이 하십시오.join다음 구문도 사용할 수 있습니다.

var pattern = new RegExp('^(([^<>()[\]\\.,;:\s@\"]+' +
  '(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@' +
  '((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|' +
  '(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$');

단순히 문자열 연산을 사용할 수 있습니다.

var pattenString = "^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|"+
"(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|"+
"(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$";
var patten = new RegExp(pattenString);

저는 모든 것을 캡슐화하고 캡처 그룹과 문자 집합을 분할하는 지원을 구현함으로써 코룬의 답변을 개선하려고 노력했습니다. - 이 방법을 훨씬 더 다양하게 만들었습니다.

이 를 이스펫을사면변함수합호니다야출해라고 .combineRegex결합해야 하는 정규 표현식 개체의 인수입니다.그 구현은 맨 아래에 있습니다.

캡처 그룹은 괄호 하나만 있으면 일부 부분이 남기 때문에 직접 분할할 수 없습니다.브라우저가 예외로 실패할 수 있습니다.

대신 캡처 그룹의 내용을 배열 안에 전달하는 것입니다.다음과 같은 경우 괄호가 자동으로 추가됩니다.combineRegex배열을 발견합니다.

또한 계량기는 무언가를 따라야 합니다.어떤 이유로 정규식을 정량자 앞에서 분할해야 하는 경우 괄호 한 쌍을 추가해야 합니다.이러한 파일은 자동으로 제거됩니다.요점은 빈 캡처 그룹은 매우 쓸모가 없으며 이러한 방식으로 정량화자는 참조해야 할 것이 있습니다.비캡처 그룹과 같은 경우에도 동일한 방법을 사용할 수 있습니다(/(?:abc)/ 되다[/()?:abc/]).

이는 간단한 예를 사용하여 가장 잘 설명할 수 있습니다.

var regex = /abcd(efghi)+jkl/;

다음이 될 것입니다.

var regex = combineRegex(
    /ab/,
    /cd/,
    [
        /ef/,
        /ghi/
    ],
    /()+jkl/    // Note the added '()' in front of '+'
);

문자집합분하야경다용객수있사습니할체를우는할을해▁if{"":[regex1, regex2, ...]}(어레대신이▁( ()[regex1, regex2, ...]되어 있으면 이든 될 수 키의 내용은 개체에 키가 하나만 포함되어 있으면 됩니다.대신에 참고하십시오.()은 야합니다해사를 사용해야 .]첫 번째 문자를 정량자로 해석할 수 있는지 여부를 더미로 시작합니다.예./[+?]/ 되다{"":[/]+?/]}

다음은 스니펫과 더 완전한 예입니다.

function combineRegexStr(dummy, ...regex)
{
    return regex.map(r => {
        if(Array.isArray(r))
            return "("+combineRegexStr(dummy, ...r).replace(dummy, "")+")";
        else if(Object.getPrototypeOf(r) === Object.getPrototypeOf({}))
            return "["+combineRegexStr(/^\]/, ...(Object.entries(r)[0][1]))+"]";
        else 
            return r.source.replace(dummy, "");
    }).join("");
}
function combineRegex(...regex)
{
    return new RegExp(combineRegexStr(/^\(\)/, ...regex));
}

//Usage:
//Original:
console.log(/abcd(?:ef[+A-Z0-9]gh)+$/.source);
//Same as:
console.log(
  combineRegex(
    /ab/,
    /cd/,
    [
      /()?:ef/,
      {"": [/]+A-Z/, /0-9/]},
      /gh/
    ],
    /()+$/
  ).source
);

개인적으로, 저는 덜 복잡한 정규식을 원합니다.

/\S+@\S+\.\S+/

네, 현재 패턴보다 정확도가 떨어지지만, 무엇을 달성하기 위해 노력하고 있습니까?사용자가 입력할 수 있는 우발적인 오류를 탐지하려고 노력하고 있습니까? 아니면 사용자가 잘못된 주소를 입력하려고 시도할까 봐 걱정하십니까?첫 번째라면 좀 더 쉬운 패턴을 택하겠어요.후자의 경우 해당 주소로 전송된 전자 메일에 응답하여 확인하는 것이 더 나은 옵션일 수 있습니다.

그러나 현재 패턴을 사용하려는 경우 다음과 같은 더 작은 하위 패턴으로 패턴을 작성하면 (IMO) 읽기가 더 쉬워지고 유지보수할 수 있습니다.

var box1 = "([^<>()[\]\\\\.,;:\s@\"]+(\\.[^<>()[\\]\\\\.,;:\s@\"]+)*)";
var box2 = "(\".+\")";

var host1 = "(\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\])";
var host2 = "(([a-zA-Z\-0-9]+\\.)+[a-zA-Z]{2,})";

var regex = new RegExp("^(" + box1 + "|" + box2 + ")@(" + host1 + "|" + host2 + ")$");

@해시브라운의 훌륭한 답변이 저를 올바른 방향으로 이끌었습니다.여기 이 블로그에서 영감을 받은 제 버전이 있습니다.

function regexp(...args) {
  function cleanup(string) {
    // remove whitespace, single and multi-line comments
    return string.replace(/\s+|\/\/.*|\/\*[\s\S]*?\*\//g, '');
  }

  function escape(string) {
    // escape regular expression
    return string.replace(/[-.*+?^${}()|[\]\\]/g, '\\$&');
  }

  function create(flags, strings, ...values) {
    let pattern = '';
    for (let i = 0; i < values.length; ++i) {
      pattern += cleanup(strings.raw[i]);  // strings are cleaned up
      pattern += escape(values[i]);        // values are escaped
    }
    pattern += cleanup(strings.raw[values.length]);
    return RegExp(pattern, flags);
  }

  if (Array.isArray(args[0])) {
    // used as a template tag (no flags)
    return create('', ...args);
  }

  // used as a function (with flags)
  return create.bind(void 0, args[0]);
}

다음과 같이 사용합니다.

regexp('i')`
  //so this is a regex

  //here I am matching some numbers
  (\d+)

  //Oh! See how I didn't need to double backslash that \d?
  ([a-z]{1,3}) /*note to self, this is group #2*/
`

작성을 RegExp객체:

/(\d+)([a-z]{1,3})/i

언급URL : https://stackoverflow.com/questions/12317049/how-to-split-a-long-regular-expression-into-multiple-lines-in-javascript

반응형