正则表达式 - 匹配范围,但每个唯一字符只有一次

时间:2017-03-13 00:43:48

标签: javascript regex regex-lookarounds

我试图通过使用正则表达式范围来避免数组和循环,但是,我只想替换范围中每个字符的第一个实例。

我使用范围是因为我无法保证订单,也无法重新订购。

例如:

"access".replace(/[access]/g, '') = "cs", instead of "". "cell phones".replace(/[el]/g) = "cl phones", instead of "c phons"

正则表达式范围内的双打无论如何都是多余的,在这种情况下,它也不应该导致第二次出现被替换。

如果这是不可能的,那么我将不得不考虑别的事情。

3 个答案:

答案 0 :(得分:2)

这需要一个后视 - 查看角色是否已经发生过,因此应该保留。但JS并不支持这一点。搜索" JS look-behind regexp"一些想法。经典的方法是反转字符串,以便您可以使用预测:



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

const testData = [
  ["access", 'access'],
  ["cell phones", 'el']
];

function match(s, chrs) {
  const reg = new RegExp(`([${chrs}])(?!.*\\1)`, "g");
  return rev(rev(s).replace(reg, ''));
}
  
testData.forEach(([input, chrs]) => console.log("input", input, "gives", match(input, chrs)));




答案 1 :(得分:0)

作为我在上述评论中所说的例子:



function replace(str, regex) {
  var cache = {};          // the cache object
  return str.replace(regex, function(m) {
    if(cache[m]) return m; // if we already removed an instance of this matched character then don't remove any further instances
    
    // otherwise ...
    cache[m] = true;       // cache the character
    return '';             // remove it
  });
}

console.log('"access", /[access]/g => ', replace("access", /[access]/g));
console.log('"cell phones", /[el]/g => ', replace("cell phones", /[el]/g));




注意:假设传递的正则表达式都只是字符集(您调用它们的范围),只允许/[...]/g,或者行为不会被取消你想要什么。

答案 2 :(得分:0)

“记住”逻辑的单行版本。

"cell phones".replace(/[el]/g, (() => { let seen = []; return m => seen.includes(m) ? m : (seen.push(m),''); })())

较短的版本:

"cell phones".replace(/[el]/g, (seen => m => m in seen ? m : seen[m] = ''))({}))