【问题标题】:How to remove word in string based on array in Javascript when word's character length in string is fewer than in array?当字符串中单词的字符长度小于数组中的字符长度时,如何根据Javascript中的数组删除字符串中的单词?
【发布时间】:2019-04-23 08:48:38
【问题描述】:

我想根据数组删除字符串中的一些单词。但是字符串中单词的字符长度小于数组中的字符长度。是否可以使用正则表达式匹配它,然后用空字符串替换它?如果没有,有什么替代方案?

我尝试使用正则表达式来匹配单词,但我无法实现。我不知道如何使正则表达式匹配数组中的至少 3 个字符。

array = ['reading', 'books'];

string = 'If you want to read the book, just read it.';

desiredOutput = 'If you want to  the , just  it.';


// Desired match

'reading' -> match for 'rea', 'read', 'readi', 'readin', 'reading'

'books' -> match for 'boo', 'book', 'books'

【问题讨论】:

    标签: javascript regex


    【解决方案1】:

    一种选择是匹配从单词边界开始的 3 个或更多单词字符,然后如果有任何单词 startsWith 相关单词,则使用替换函数返回空字符串:

    const array = ['reading', 'books'];
    const string = 'If you want to read the book, just read it.';
    const output = string.replace(
      /\b\w{3,}/g,
      word => array.some(item => item.startsWith(word)) ? '' : word
    );
    console.log(output);

    【讨论】:

      【解决方案2】:

      The answer from CertainPerformance 更好 - 更易于实现和维护,但值得注意的是 - 您还可以从数组生成正则表达式。

      这个想法很简单——如果你想匹配rrereareadreadireadinreading,那么正则表达式就是reading|readin|readi|read|rea|re|r。您首先需要最长变化的原因是因为否则正则表达式引擎将在 finds 中的第一个匹配项处停止:

      let regex = /r|re|rea|read/g
      //           ↑_________________
      console.log(               //  |
        "read".replace(regex, "")//  |
      // ↑___________________________|
      )

      所以你可以把一个词分解成这种模式来生成一个正则表达式

      function allSubstrings(word) {
        let substrings = [];
        for (let i = word.length; i > 0; i--) {
          let sub = word.slice(0, i);
          substrings.push(sub)
        }
        
        return substrings;
      }
      
      console.log(allSubstrings("reading"))

      这样您就可以简单地生成所需的正则表达式。

      function allSubstrings(word) {
        let substrings = [];
        for (let i = word.length; i > 0; i--) {
          let sub = word.slice(0, i);
          substrings.push(sub)
        }
        
        return substrings;
      }
      
      function toPattern(word) {
        let substrings = allSubstrings(word);
        let pattern = substrings.join("|");
        
        return pattern;
      }
      
      console.log(toPattern("reading"))

      最后是获取一个数组并将其转换为正则表达式。这需要处理每个单词,然后将每个单独的正则表达式组合成一个匹配任何单词的正则表达式:

      const array = ['reading', 'books'];
      const string = 'If you want to read the book, just read it.';
      
      //generate the pattern
      let pattern = array
        .map(toPattern) //first, for each word
        .join("|"); //join patterns for all words
        
      //convert the pattern to a regex
      let regex = new RegExp(pattern, "g"); 
      
      let result = string.replace(regex, "");
      
      //desiredOutput: 'If you want to  the , just  it.';
      console.log(result); 
      
      
      function allSubstrings(word) {
        let substrings = [];
        for (let i = word.length; i > 0; i--) {
          let sub = word.slice(0, i);
          substrings.push(sub)
        }
        
        return substrings;
      }
      
      function toPattern(word) {
        let substrings = allSubstrings(word);
        let pattern = substrings.join("|");
        
        return pattern;
      }

      所以,这是如何您可以从该数组生成正则表达式。在 this 的情况下,这是可行的,但不能保证,因为它可能会匹配你不想要的东西。例如,r 将匹配 any 字符,它不一定需要在与之匹配的单词中。

      const array = ['reading'];
      const string = 'The quick brown fox jumps over the lazy dog';
      //                         ^                 ^    
      
      let pattern = array
        .map(word => allSubstrings(word).join("|"))
        .join("|");
      
      let regex = new RegExp(pattern, "g"); 
      let result = string.replace(regex, "");
      
      console.log(result); 
      
      function allSubstrings(word) {
        let substrings = [];
        for (let i = word.length; i > 0; i--) {
          let sub = word.slice(0, i);
          substrings.push(sub)
        }
        
        return substrings;
      }

      这会变得更复杂,因为您想为每个单词生成更复杂的模式。您通常希望匹配单词,因此您可以使用单词边界字符\b,这意味着“阅读”的模式现在可以如下所示:

      \breading\b|\breadin\b|\breadi\b|\bread\b|\brea\b|\bre\b|\br\b
      ↑↑       ↑↑ ↑↑      ↑↑ ↑↑     ↑↑ ↑↑    ↑↑ ↑↑   ↑↑ ↑↑  ↑↑ ↑↑ ↑↑
      

      为了保持输出至少有点可读性,可以将其放在一个组中,然后将整个组匹配一个单词:

      \b(?:reading|readin|readi|read|rea|re|r)\b
         ↑↑
         ||____ non-capturing group
      

      所以,你必须生成这个模式

      function toPattern(word) {
        let substrings = allSubstrings(word);
        //escape backslashes, because this is a string literal and we need \b as content
        let pattern = "\\b(?:" + substrings.join("|") + ")\\b"; 
      
        return pattern;
      }
      

      这导致我们这样做

      const array = ['reading', 'books'];
      const string = 'The quick brown fox jumps over the lazy dog. If you want to read the book, just read it.';
      
      let pattern = array
        .map(toPattern)
        .join("|");
        
      let regex = new RegExp(pattern, "g");
      let result = string.replace(regex, "");
      
      console.log(result); 
      
      
      function allSubstrings(word) {
        let substrings = [];
        for (let i = word.length; i > 0; i--) {
          let sub = word.slice(0, i);
          substrings.push(sub)
        }
        
        return substrings;
      }
      
      function toPattern(word) {
        let substrings = allSubstrings(word);
        let pattern = "\\b(?:" + substrings.join("|") + ")\\b";
        
        return pattern;
      }

      这足以解决您的任务。所以生成一个正则表达式是可能的。最后一个看起来像这样:

      /\b(?:reading|readin|readi|read|rea|re|r)\b|\b(?:books|book|boo|bo|b)\b/g
      

      但它的大部分生成都花在尝试生成有效的东西。这不一定是一个复杂的解决方案,但如前所述,CertainPerformance 建议的解决方案更好,因为它更简单,这意味着它失败的可能性更小,并且将来更容易维护。

      【讨论】:

        【解决方案3】:

        我不知道直接的方法,但您可以创建自己的正则表达式模式,如下所示:

        // This function create a regex pattern string for each word in the array.
        // The str is the string value (the word), 
        // min is the minimum required letters in eac h word 
        function getRegexWithMinChars(str, min) {
            var charArr = str.split("");
            var length = charArr.length;
            var regexpStr = "";
            for(var i = 0; i < length; i++){
                regexpStr +="[" + charArr[i] + "]" + (i < min ? "" : "?");
            }
            return regexpStr;
        }
        
        // This function returns a regexp object with the patters of the words in the array
        function getStrArrayRegExWithMinChars(strArr, min) {
            var length = strArr.length;
            var regexpStr = "";
            for(var i = 0; i < length; i++) {
                regexpStr += "(" + getRegexWithMinChars(strArr[i], min) + ")?";
            }
            return new RegExp(regexpStr, "gm");
        }
        
        var regexp = getStrArrayRegExWithMinChars(searchArr, 3);
        
        // With the given regexp I was able to use string replace to 
        // find and replace all the words in the string
        str.replace(regexp, "");
        
        //The same can be done with one ES6 function
        const getStrArrayRegExWithMinChars = (searchArr, min) => {
            return searchArr.reduce((wordsPatt, word) => {
                const patt = word.split("").reduce((wordPatt, letter, index) => {
                        return wordPatt + "[" + letter + "]" + (index < min ? "" : "?");
                    },"");
                return wordsPatt + "(" + patt + ")?";
            }, "");
        }
        
        var regexp = getStrArrayRegExWithMinChars(searchArr, 3);
        
        // With the given regexp I was able to use string replace to 
        // find and replace all the words in the string
        str.replace(regexp, "");
        

        【讨论】:

          猜你喜欢
          • 2014-12-16
          • 2020-08-22
          • 1970-01-01
          • 1970-01-01
          • 2017-11-03
          • 1970-01-01
          • 1970-01-01
          • 2022-12-10
          • 1970-01-01
          相关资源
          最近更新 更多