programing

자바스크립트에서 동등한 것에 대한 부정적인 뒤보기

codeshow 2023. 10. 29. 20:02
반응형

자바스크립트에서 동등한 것에 대한 부정적인 뒤보기

자바스크립트 정규 표현식에서 부정적인 느낌을 얻을 수 있는 방법이 있습니까?특정 문자 집합으로 시작하지 않는 문자열을 일치시켜야 합니다.

문자열 시작 부분에 일치하는 부분이 있으면 실패하지 않고 이렇게 하는 regex를 찾을 수 없는 것 같습니다.부정적인 시선이 유일한 답인 것 같지만 자바스크립트에는 없습니다.

이것은 제가 일하고 싶은 정규 근무제입니다만, 그렇지 않습니다.

(?<!([abcdefg]))m

따라서 jim 또는 m의 m과 일치하지만 jam은 일치하지 않습니다.

2018년부터 Look behind AssertionsECMA스크립트 언어 사양의 일부입니다.

// positive lookbehind
(?<=...)
// negative lookbehind
(?<!...)

2018년 이전 답변

자바스크립트는 네거티브 룩어헤드를 지원하므로 이를 위한 한 가지 방법은 다음과 같습니다.

  1. 입력 문자열을 반전합니다.

  2. 역수와 일치.

  3. 성냥을 되돌리고 다시 포맷합니다.


const reverse = s => s.split('').reverse().join('');

const test = (stringToTests, reversedRegexp) => stringToTests
  .map(reverse)
  .forEach((s,i) => {
    const match = reversedRegexp.test(s);
    console.log(stringToTests[i], match, 'token:', match ? reverse(reversedRegexp.exec(s)[0]) : 'Ø');
  });

예 1:

@andrew-ensley의 질문에 따라:

test(['jim', 'm', 'jam'], /m(?!([abcdefg]))/)

출력:

jim true token: m
m true token: m
jam false token: Ø

예 2:

@neaumusic comment ()max-height그러나 그렇지는line-height, 상징적 존재height):

test(['max-height', 'line-height'], /thgieh(?!(-enil))/)

출력:

max-height true token: height
line-height false token: Ø

Look behind Assertions는 2018년 ECMA스크립트 사양승인되었습니다.

긍정적인 사용법 이면:

console.log(
  "$9.99  €8.47".match(/(?<=\$)\d+\.\d*/) // Matches "9.99"
);

부정적인 사용법:

console.log(
  "$9.99  €8.47".match(/(?<!\$)\d+\.\d*/) // Matches "8.47"
);

플랫폼 지원

  • ✔️ V8
    • ✔ ️ 구글 크롬 62.0
    • ✔ ️ Microsoft Edge 79.0
    • Node.js 6.0은 플래그 뒤에, 9.0은 플래그 뒤에 있습니다.
    • ✔ ️ Deno (모든버전)
  • ✔️거미원숭이
  • ✔ ️ 자바스크립트코어: 기능이 병합되었습니다
    • ✔️ 애플 사파리 16.4
    • ✔ ️ iOS 16.4 WebView (iOS + iPad의 모든 브라우저)OS)
    • ✔️0.2.2
  • ❌ Chakra: 마이크로소프트사에서 작업중이었으나 현재 Chakra는 V8을 선호하여 포기되었습니다.
    • ❌ 인터넷 익스플로러
    • ❌ 79 이전 버전의 Edge(Edge 기반 버전HTML+차크라)

당신이 모든 것을 찾고 싶어한다고 가정해봅시다.int에 뒤지지 않는unsigned :

부정적인 전망에 대한 지원으로:

(?<!unsigned )int

부정적인 전망에 대한 지원이 없는 경우:

((?!unsigned ).{9}|^.{0,8})int

기본적으로 선행 문자를 잡고 부정적인 전망으로 매칭을 배제하는 것이 아이디어지만 선행 문자 n개가 없는 경우도 매칭합니다.(여기서 n은 뒤를 보는 길이입니다).

그럼 문제의 정규군은?

(?<!([abcdefg]))m

다음과 같이 번역됩니다.

((?!([abcdefg])).|^)m

캡처 그룹을 사용하여 관심 있는 문자열의 정확한 위치를 찾거나 특정 부분을 다른 것으로 교체하려는 경우가 있습니다.

Mijoja의 전략은 당신의 특정한 경우에는 효과가 있지만 일반적인 경우에는 효과가 없습니다.

js>newString = "Fall ball bill balll llama".replace(/(ba)?ll/g,
   function($0,$1){ return $1?$0:"[match]";});
Fa[match] ball bi[match] balll [match]ama

여기에 더블 L을 맞추는 것이 목표이지만 "ba" 앞에 올 경우에는 그렇지 않은 예가 있습니다."ball"이라는 단어에 주목하세요. 진정한 뒤의 모습은 첫 번째 2l를 억제해야 하지만 두 번째 쌍과 일치해야 합니다.그러나 처음 2l를 일치시킨 다음 해당 일치를 false positive로 무시하면 regexp 엔진은 해당 일치가 끝날 때부터 진행되며 false positive 내의 모든 문자를 무시합니다.

사용하다

newString = string.replace(/([abcdefg])?m/, function($0,$1){ return $1?$0:'m';});

문자 집합을 부정하여 캡처하지 않는 그룹을 정의할 수 있습니다.

(?:[^a-g])m

할 겁니다...모든 것이 일치할 것입니다.m 그 어떤 글자도 앞에 붙지 않았습니다.

이것이 제가 성취한 방법입니다.str.split(/(?<!^)@/)Node.js 8의 경우(뒤보기를 지원하지 않음):

str.split('').reverse().join('').split(/@(?!$)/).map(s => s.split('').reverse().join('')).reverse()

작동? 네 (유니코드 테스트 안됨)불쾌해요?네.

Mijoja의 아이디어를 따라 그리고 JasonS에 의해 노출된 문제들로부터 끌어내어, 나는 이 아이디어를 가지고 있었습니다; 나는 조금 확인했지만 나 자신을 확신할 수 없기 때문에 js regex에서 나보다 더 전문가인 누군가의 검증이 좋을 것 같습니다 :)

var re = /(?=(..|^.?)(ll))/g
         // matches empty string position
         // whenever this position is followed by
         // a string of length equal or inferior (in case of "^")
         // to "lookbehind" value
         // + actual value we would want to match

,   str = "Fall ball bill balll llama"

,   str_done = str
,   len_difference = 0
,   doer = function (where_in_str, to_replace)
    {
        str_done = str_done.slice(0, where_in_str + len_difference)
        +   "[match]"
        +   str_done.slice(where_in_str + len_difference + to_replace.length)

        len_difference = str_done.length - str.length
            /*  if str smaller:
                    len_difference will be positive
                else will be negative
            */

    }   /*  the actual function that would do whatever we want to do
            with the matches;
            this above is only an example from Jason's */



        /*  function input of .replace(),
            only there to test the value of $behind
            and if negative, call doer() with interesting parameters */
,   checker = function ($match, $behind, $after, $where, $str)
    {
        if ($behind !== "ba")
            doer
            (
                $where + $behind.length
            ,   $after
                /*  one will choose the interesting arguments
                    to give to the doer, it's only an example */
            )
        return $match // empty string anyhow, but well
    }
str.replace(re, checker)
console.log(str_done)

개인적인 산출물:

Fa[match] ball bi[match] bal[match] [match]ama

부름이 원칙입니다checker두 문자 사이의 문자열의 각 지점에서 해당 위치가 다음의 시작점이 될 때마다:

--- 필요하지 않은 것의 크기의 부분 문자열(여기서)'ba',따라서..) (해당 크기를 알고 있다면, 그렇지 않으면 아마 더 어려울 것입니다.)

--- --- 또는 문자열의 시작일 경우 그보다 작습니다.^.?

이 일을 계기로

--- 실제로 구해야 할 것(여기)'ll').

전화할 때마다checker, 이전의 값을 확인하기 위한 테스트가 있을 것입니다.ll우리가 원하지 않는 것이 아닙니다 (!== 'ba'); 그렇다면 다른 함수를 호출하고, 이 함수여야 합니다 (doerstr 에합니다 하는 데 만약 이것이 목적이거나 더 일반적으로 검색 결과를 수동으로 처리하는 데 필요한 데이터를 입력합니다.str.

여기서 우리는 문자열을 바꾸어서 우리는 주어진 위치를 상쇄하기 위해 길이의 차이를 추적할 필요가 있었습니다.replace, 모두 에 계산하여str, 그 자체는 절대 변하지 않습니다.

원시 문자열은 불변이기 때문에, 우리는 그 변수를 사용할 수 있었습니다.str전체 연산의 결과를 저장하는 것이지만, 나는 이미 교체로 인해 복잡해진 예제가 다른 변수로 더 명확할 것이라고 생각했습니다.str_done).

공연적인 면에서는 꽤 가혹할 것이라고 생각합니다. "를 ""로 무의미하게 대체하는 모든 것들,this str.length-1시간, 그리고 여기 수동으로 교체하는 것이 많은 절단을 의미합니다.아마도 이 특정한 위의 경우, 우리가 삽입하고 싶은 곳 주변에서 줄을 한 번만 잘라냄으로써 그룹화될 수 있을 것입니다.[match]그리고..join()와 함께.[match]그 자체.

또 하나는 더 복잡한 사건들을 어떻게 다룰지 모른다는 거죠. 즉, 뒤에 보이는 가짜에 대한 복잡한 가치들 말이죠.길이는 아마도 가장 문제가 많은 데이터일 것입니다.

그리고,checker, $back에 대해 여러 개의 원하지 않는 값이 발생할 가능성이 있는 경우, 우리는 외부에서 또 다른 regex(캐싱(생성)될)를 사용하여 테스트를 수행해야 합니다.checker를 호출할 때마다 동일한 regex 개체가 생성되지 않도록 하는 것이 최선입니다.checker그것이 우리가 회피하고자 하는 것인지 아닌지를 알 수 있습니다.

제가 분명히 했길 바랍니다; 주저하지 않는다면, 저는 더 잘 노력할 것입니다.:)

당신의 케이스를 이용해서, 만약 당신이 대체하기를 원한다면, m예를 들어 그것을 대문자로 바꾸는 것과 같이.M, 캡처 그룹에서 set을 negative 할 수 있습니다.

경기([^a-g])m, 대신에$1M

"jim jam".replace(/([^a-g])m/g, "$1M")
\\jiM jam

([^a-g])어떤 문자와도 일치합니다().^)에서a-g범위를 지정하고 첫 번째 캡처 그룹에 저장하여 다음과 같이 액세스할 수 있습니다.$1.

그래서 우리는 발견합니다.im인에jim로 교체합니다.iM결과적으로jiM.

앞서 언급했듯이 자바스크립트는 이제 뒤를 볼 수 있게 되었습니다.이전 브라우저에서는 여전히 해결 방법이 필요합니다.

내 머릿속에는 정확하게 결과를 전달하는 뒤를 돌아보지 않고는 레젝스를 찾을 방법이 없을 거라고 장담합니다.당신이 할 수 있는 일은 그룹들과 함께 일하는 것뿐입니다.정규군이 있다고 가정해 보겠습니다.(?<!Before)Wanted,어디에Wanted당신이 매치하고 싶은 regex와.Before는 일치하기 전에 무엇이 없어야 하는지를 카운트하는 정규군입니다.당신이 할 수 있는 최선은 레지렉스를 부정하는 것입니다.Beforeregex를 사용합니다.NotBefore(Wanted). 원하는 결과는 첫 번째 그룹입니다.$1.

고객님의 경우Before=[abcdefg]부정하기 쉬운.NotBefore=[^abcdefg]. 그래서 정규군은[^abcdefg](m). 당신이 필요한 위치는Wanted, 당신은 조를 짜야합니다.NotBefore또한, 원하는 결과가 두 번째 그룹입니다.

일치하는 경우Before패턴이 일정한 길이를 가지런히n, 즉, 패턴이 반복되는 토큰을 포함하지 않는 경우, 당신은 다음을 부정하는 것을 피할 수 있습니다.Before패턴을 만들어 정규식을 사용합니다.(?!Before).{n}(Wanted), 하지만 여전히 첫번째 그룹을 사용하거나 정규 표현을 사용해야 합니다.(?!Before)(.{n})(Wanted)두번째 그룹을 사용합니다.이 예제에서 패턴은Before실제로는 1이라는 고정된 길이를 가지고 있으므로 regex를 사용합니다.(?![abcdefg]).(m)아니면(?![abcdefg])(.)(m). 모든 일치 항목에 관심이 있는 경우 다음을 추가합니다.g플래그, 내 코드 스니펫 참조:

function TestSORegEx() {
  var s = "Donald Trump doesn't like jam, but Homer Simpson does.";
  var reg = /(?![abcdefg])(.{1})(m)/gm;
  var out = "Matches and groups of the regex " + 
            "/(?![abcdefg])(.{1})(m)/gm in \ns = \"" + s + "\"";
  var match = reg.exec(s);
  while(match) {
    var start = match.index + match[1].length;
    out += "\nWhole match: " + match[0] + ", starts at: " + match.index
        +  ". Desired match: " + match[2] + ", starts at: " + start + ".";   
    match = reg.exec(s);
  }
  out += "\nResulting string after statement s.replace(reg, \"$1*$2*\")\n"
         + s.replace(reg, "$1*$2*");
  alert(out);
}

이렇게 하면 효과적입니다.

"jim".match(/[^a-g]m/)
> ["im"]
"jam".match(/[^a-g]m/)
> null

예제 검색 및 바꾸기

"jim jam".replace(/([^a-g])m/g, "$1M")
> "jiM jam"

이 작업을 수행하려면 음의 뒤로 가기 문자열이 1자 길이여야 합니다.

언급URL : https://stackoverflow.com/questions/641407/negative-lookbehind-equivalent-in-javascript

반응형