Как удалить слово в строке на основе массива в Javascript, когда длина слова в строке меньше, чем в массиве? - PullRequest
1 голос
/ 23 апреля 2019

Я хочу удалить несколько слов в строке на основе массива. Но длина слова в строке меньше, чем в массиве. Можно ли сопоставить его с помощью регулярных выражений, а затем заменить его пустой строкой? Если нет, то какие есть альтернативы?

Я пытался использовать регулярное выражение, чтобы соответствовать слову, но я не могу этого достичь. Я не знаю, как заставить регулярное выражение соответствовать минимум 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'

Ответы [ 3 ]

1 голос
/ 23 апреля 2019

Ответ от CertainPerformance лучше - проще в реализации и обслуживании, но стоит отметить, что вы также можете сгенерировать регулярное выражение из массива.

Идея достаточно проста - если вы хотите сопоставить r, re, rea, read, readi, readin, reading, регулярное выражение для этого будет reading|readin|readi|read|rea|re|r. Причина, по которой вы хотите сначала самый длинный вариант, заключается в том, что в противном случае механизм регулярных выражений остановится при первом совпадении:

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;
}

Итак, как вы можете сгенерировать регулярное выражение из этого массива. В этом случае это работает, но это не гарантируется, потому что есть опасность, что оно может соответствовать тому, что вы не хотите. Например, r будет соответствовать любому символу, это не обязательно должно быть в слове, которое соответствует этому.

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 лучше, потому что оно проще, что означает меньшую вероятность его сбоя, и его будет проще поддерживать в будущем.

1 голос
/ 23 апреля 2019

Один из вариантов - сопоставить 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);
0 голосов
/ 23 апреля 2019

Я не знаю прямого способа сделать это, но вы можете создать свой собственный шаблон регулярных выражений, например, так:

// 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, "");
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...