Замените переменную строку на regex nodejs

#javascript #node.js #regex

#javascript #node.js #регулярное выражение

Вопрос:

Мне нужно определить шаблоны, подобные приведенным ниже, внутри очень большой строки и заменить их на «null»:

["pmeta", ["ImageSelectStoreFront", null, 3, 4, 2, null, "Storefront", []]],
["pmeta", ["/m/01pns0", null, 3, 3, 3, null, "fire hydrant", []], null, [1]],
["pmeta", ["/m/0199g", null, 3, 3, 3, null, "bicycle", []], null, [1]],

Эти строки выглядят как JSON, но строка, в которой они отображаются, не является JSON, поэтому нет смысла ее разбирать. Мне также не нужно анализировать этот JSON, мне нужно удалить его из строки, в которой он появляется.

Единственные части, которые всегда одинаковы, — это ["pmeta", и закрывающая скобка и запятая в конце.

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

Кто-нибудь может дать мне несколько указателей на регулярные выражения или предложить другие способы достижения этого?

Комментарии:

1. Вместо этого проанализируйте JSON

2. Неясно, что вы хотите заменить

3. @CertainPerformance Это на самом деле не было бы полезно для меня. Этот JSON отображается в строке, и мне нужно избавиться от него, а не анализировать его.

4. @adiga Мне нужно заменить любую строку, которая начинается с ["pmeta", и заканчивается последней, закрывающей скобкой, и все, что находится между ними.

5. Выполните синтаксический анализ JSON -> filter -> serialise в JSON, это должно быть намного проще. Регулярное выражение будет очень неудобно писать и поддерживать. Пользовательский анализатор был бы проще для сравнения, но все равно требует намного больше работы, чем тривиальный синтаксический анализ -> фильтр -> сериализация.

Ответ №1:

Вместо регулярного выражения вы могли бы выполнить пользовательский синтаксический анализ. Это работает следующим образом:

  1. Найдите, есть ли во входных данных что-либо, начинающееся с ["pmeta" .
  2. Считайте, что startIndex
  3. Найдите индекс последней закрывающей скобки после этого индекса, сохранив стопку скобок. Вы добавляете по одному элементу в стек для каждой открытой скобки, удаляете элемент для любой закрывающей скобки. Когда вы очищаете стек, это последняя закрывающая скобка. Считайте это как endIndex
  4. Найдите раздел строки от startIndex до endIndex и затем замените его на null .

Я сократил (и обезличил) ваш образец, заменив длинные значения на отдельные слова:

 let input = `)]}'
["rresp",
"one",
null,
120,
["pmeta",["/m/01pns0",null,3,3,3,null,"fire hydrant",[]
]
,null,[1]
]
,"dynamic",null,["bgdata","two","","three"]
,"four","five"]`

let output = clean(input);
console.log("output", output);

function clean(text) {
  let startIndex = text.indexOf('["pmeta"');

  //nothing to remove - early exit
  if (startIndex === -1) return text; 

  let endIndex = findLastOpenBracket(text, startIndex);
  
  let toReplace = text.substring(startIndex, endIndex);
  console.log("found text to replace:", toReplace);
  
  return text.replace(toReplace, "null")
}

function findLastOpenBracket(text, startIndex) {
  let openBrackets = [];
  
  for (let i = startIndex; i < text.length; i  ) {
    let char = text[i];
    if (char === "[") {
      openBrackets.push(char);
    } else if (char === "]") {
      openBrackets.pop()
      
      if(openBrackets.length === 0){
        return i   1
      }
    }
  }
}  

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

Еще одно замечание: шаг 4. немного громоздок. К сожалению, в JavaScript нет .splice метода для строк, поэтому вам придется пойти длинным путем — получить подстроку -> заменить подстроку в строке. Вы можете вместо этого использовать Array.splice() метод, если это необходимо, но я также нахожу его громоздким:

 let text = "one,two,three";

//replace "two"
let startIndex = 4;
let endIndex = 7;


let arr = text.split("");
arr.splice(
  startIndex, 
  endIndex - startIndex, 
  "null"
)

let output = arr.join("");
console.log(output);  

Комментарии:

1. Большое спасибо за вашу помощь, я рассмотрю это решение завтра — уже очень поздно 🙂

2. Некоторые последующие мысли — я только что понял, что сохранение стека для скобок здесь излишне. Вы могли бы сделать это с помощью одного счетчика openBrackets = 0 и увеличивать его для каждой открытой скобки, уменьшать его для каждой закрытой. Я думаю, это лучше, но, как я уже сказал, есть многое, что можно улучшить для этой функции. Это может быть обобщено на любой тип скобок и / или кавычек. Однако я оставлю все как есть.

Ответ №2:

Предполагая, что в строке есть только одно вхождение шаблона, и что никаких других вхождений ], then ["pmeta",.*], не может работать. Демонстрация регулярного выражения: https://regex101.com/r/4DSfVR/1

Реализация JavaScript:

 inputstr = 'djfhjkdfhkhdf ["pmeta", ["ImageSelectStoreFront", null, 3, 4, 2, null, "Storefront", []]],jdkfhkjdhf';
pattern = new RegExp('\["pmeta",.*\],',"gm");
console.log(inputstr.replace(pattern,""));  

Комментарии:

1. Это не работает с примером операции, опубликованным в комментариях

2. @Joxrox но это буквально не работает в примере, который вы опубликовали

3. @VLAZ верно. Я не видел вставку перед публикацией. Как я уже упоминал, это регулярное выражение работает только в том случае, если нет других случаев ], . Я также не учел, что шаблон может содержать новые строки ( s флаг позаботится об этом).