2015-07-22 3 views
3

Существует несколько (иногда сложных) решений для регулярных выражений lookbehind в Javascript. Но, что является самым простым способом, если мне нужна нулевая ширина ! смотреть за выражением с глобальным поиском, который может перекрываться. Например. с помощью /(?<=[01])\d/g мы могли бы сделать следующее:Javascript Lookbehind with Global Search Overlapped

var a = "--1--01001--1087---"; 
a.replace(/(?<=[01])\d/g, "#"); 
// This should return "--1--0####--1##7---" if lookbehind would be supported 

Или другой пример: Как мы можем создать \b как выражение, которое работает только с буквами ([a-zA-Z]). (Lookforward - это не вопрос. Просто JS не поддерживает lookbehind).

ответ

1

вид сзади через реверс подход кажется самым легким здесь. Этот подход лучше всего подходит для коротких числовых шаблонов, подобных этому.

function revStr(str) { 
 
    return str.split('').reverse().join(''); 
 
} 
 

 
var s = "--1--01001--1087---"; 
 
var rxp = /\d(?=[01])/g; 
 

 
var result = revStr(revStr(s).replace(rxp, "#")); 
 
document.write(result);

Логика:

  • \d(?=[01]) является обратным регулярным выражением для (?<=[01])\d
  • Мы реверс строки ввода с revStr(s) функцией
  • Мы обратный результатом замены снова, чтобы получить конечный результат.

ПРИМЕЧАНИЕ:

В случае, если вам нужен как переменная ширина взгляд-за и упреждающими в JavaScript, я могу рекомендовать чтение JavaScript Regex Lookbehind Redux статьи Стивена Levithan, где вы можете найти образец функция, показывающая, как реализовать это поведение, используя XRegExp. Вот функции:

// Simulating infinite-length leading lookbehind in JavaScript. Uses XRegExp. 
// Captures within lookbehind are not included in match results. Lazy 
// repetition in lookbehind may lead to unexpected results. 

(function (XRegExp) { 

    function prepareLb(lb) { 
     // Allow mode modifier before lookbehind 
     var parts = /^((?:\(\?[\w$]+\))?)\(\?<([=!])([\s\S]*)\)$/.exec(lb); 
     return { 
      // $(?!\s) allows use of (?m) in lookbehind 
      lb: XRegExp(parts ? parts[1] + "(?:" + parts[3] + ")$(?!\\s)" : lb), 
      // Positive or negative lookbehind. Use positive if no lookbehind group 
      type: parts ? parts[2] === "=" : !parts 
     }; 
    } 

    XRegExp.execLb = function (str, lb, regex) { 
     var pos = 0, match, leftContext; 
     lb = prepareLb(lb); 
     while (match = XRegExp.exec(str, regex, pos)) { 
      leftContext = str.slice(0, match.index); 
      if (lb.type === lb.lb.test(leftContext)) { 
       return match; 
      } 
      pos = match.index + 1; 
     } 
     return null; 
    }; 

    XRegExp.testLb = function (str, lb, regex) { 
     return !!XRegExp.execLb(str, lb, regex); 
    }; 

    XRegExp.searchLb = function (str, lb, regex) { 
     var match = XRegExp.execLb(str, lb, regex); 
     return match ? match.index : -1; 
    }; 

    XRegExp.matchAllLb = function (str, lb, regex) { 
     var matches = [], pos = 0, match, leftContext; 
     lb = prepareLb(lb); 
     while (match = XRegExp.exec(str, regex, pos)) { 
      leftContext = str.slice(0, match.index); 
      if (lb.type === lb.lb.test(leftContext)) { 
       matches.push(match[0]); 
       pos = match.index + (match[0].length || 1); 
      } else { 
       pos = match.index + 1; 
      } 
     } 
     return matches; 
    }; 

    XRegExp.replaceLb = function (str, lb, regex, replacement) { 
     var output = "", pos = 0, lastEnd = 0, match, leftContext; 
     lb = prepareLb(lb); 
     while (match = XRegExp.exec(str, regex, pos)) { 
      leftContext = str.slice(0, match.index); 
      if (lb.type === lb.lb.test(leftContext)) { 
       // Doesn't work correctly if lookahead in regex looks outside of the match 
       output += str.slice(lastEnd, match.index) + XRegExp.replace(match[0], regex, replacement); 
       lastEnd = match.index + match[0].length; 
       if (!regex.global) { 
        break; 
       } 
       pos = match.index + (match[0].length || 1); 
      } else { 
       pos = match.index + 1; 
      } 
     } 
     return output + str.slice(lastEnd); 
    }; 

}(XRegExp)); 

Каждая из этих функций принимает три аргумента: строка для поиска, шаблон просмотра назад в виде строки (можно использовать XRegExp расширения синтаксиса), а главное регулярное выражение. XRegExp.replaceLb принимает четвертый аргумент для значения замены, которое может быть строкой или функцией.

Примеры использования следуют:

XRegExp.execLb("Fluffy cat", "(?i)(?<=fluffy\\W+)", XRegExp("(?i)(?<first>c)at")); 
// -> ["cat", "c"] 
// Result has named backref: result.first -> "c" 

XRegExp.execLb("Fluffy cat", "(?i)(?<!fluffy\\W+)", /cat/i); 
// -> null 

XRegExp.testLb("Fluffy cat", "(?i)(?<=fluffy\\W+)", /cat/i); 
// -> true 

XRegExp.testLb("Fluffy cat", "(?i)(?<!fluffy\\W+)", /cat/i); 
// -> false 

XRegExp.searchLb("Catwoman's fluffy cat", "(?i)(?<=fluffy\\W+)", /cat/i); 
// -> 18 

XRegExp.searchLb("Catwoman's fluffy cat", "(?i)(?<!fluffy\\W+)", /cat/i); 
// -> 0 

XRegExp.matchAllLb("Catwoman's cats are fluffy cats", "(?i)(?<=fluffy\\W+)", /cat\w*/i); 
// -> ["cats"] 

XRegExp.matchAllLb("Catwoman's cats are fluffy cats", "(?i)(?<!fluffy\\W+)", /cat\w*/i); 
// -> ["Catwoman", "cats"] 

XRegExp.replaceLb("Catwoman's fluffy cat is a cat", "(?i)(?<=fluffy\\W+)", /cat/ig, "dog"); 
// -> "Catwoman's fluffy dog is a cat" 

XRegExp.replaceLb("Catwoman's fluffy cat is a cat", "(?i)(?<!fluffy\\W+)", /cat/ig, "dog"); 
// -> "dogwoman's fluffy cat is a dog" 

XRegExp.replaceLb("Catwoman's fluffy cat is a cat", "(?i)(?<!fluffy\\W+)", /cat/ig, function ($0) { 
    var first = $0.charAt(0); 
    return first === first.toUpperCase() ? "Dog" : "dog"; 
}); 
// -> "Dogwoman's fluffy cat is a dog" 
+0

Если вы не нуждаетесь в переменной ширины Двойник позади с переменной шириной, заглядывая вперёд, этот поворот подход, кажется, работает лучше всего для перекрытия матчей. И количество кода не так уж и велико. Кроме того, шаблоны регулярных выражений не так трудно отменить. –

+0

Я нахожу это сказанным, но, похоже, нет другого выбора. На самом деле, иногда нам также нужно как смотреть, так и смотреть вперед (не часто: я думаю, я использовал его примерно 5 раз в течение 16 лет Perl, но все же). – FERcsI

+0

Если вам нужен как внешний вид с переменной шириной, так и внешний вид в JavaScript, я могу порекомендовать прочитать статью [JavaScript Regex Lookbehind Redux] (http://blog.stevenlevithan.com/archives/javascript-regex-lookbehind) Стивен Левитан, где вы можете найти примерную функцию, показывающую, как реализовать это поведение с помощью [XRegExp] (https://github.com/slevithan/xregexp). –