Заменить строку не в одной из нескольких возможных многосимвольных оболочек - PullRequest
0 голосов
/ 27 января 2019

Я хотел бы проанализировать строку с JavaScript .replace, , за исключением , если она находится между несколькими парами разделителей. Какой способ сделать это является самым простым, и, надеюсь, наиболее общим и / или эффективным?

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

В этой конкретной ситуации я хочу заменить экземпляры ++, за которыми сразу следует хотя бы один не плюс символ, за которым сразу следует ++, только с вложенным текстом, заглавными буквами - за исключением случаев, когда между , но необязательно непосредственно предшествует / сопровождается @< и >@ или @@ и @@.

var options = {
    '@<': ['>@', 5, 2],
    '@@': ['@@', 2, 2]
},
possiblyParse = str => str.replace(/(@<|@@|^).+?(>@|@@|$)/g, (a, b, c) =>
    options.hasOwnProperty(b) && options[b][0] == c ?
    a.slice(options[b][1], a.length - options[b][2]) : // If string suitably enclosed, return it without delimiters
    a.replace(/\+\+([^\+]+)\+\+/g, (a, b) => b.toUpperCase())); // Otherwise, do something, keeping delimiter(s) if any
console.log(possiblyParse('input'));

Этот код дает эти приемлемые результаты ...

console.log(possiblyParse('++abc++'))); // ABC
console.log(possiblyParse('@<++abc++>@')); // ++abc++
console.log(possiblyParse('@@++abc++@@')); // ++abc++
console.log(possiblyParse('@<++abc++@@')); // @<ABC@@
console.log(possiblyParse('@@++abc++>@')); // @@ABC>@
console.log(possiblyParse('@<++abc++')); // @<ABC
console.log(possiblyParse('++abc++@@')); // ABC@@

… и терпит неудачу здесь:

console.log(possiblyParse('z@<@++abc++>@')) // z@<ABC>@, should be z++abc++
console.log(possiblyParse('++abc++ @<@++abc++>@')) // ABC @<ABC>@, should be ABC ++abc++

Я подозреваю, что проблема с моим регулярным выражением, /(@<|@@|^).+?(>@|@@|$)/g, которое, как мне кажется, соответствует @<, @@ или началу ввода, затем лениво соответствует хотя бы одному символу, затем соответствует >@, @@ или конец ввода. Можете ли вы помочь решить эту проблему?

1 Ответ

0 голосов
/ 28 января 2019

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

Мое решение просто кодирует каждую строку в любом из возможных разделителей, так что результат не содержит пар ++, затем использует заглавные буквы, а затем декодирует все закодированные строки.

var encodeWithOrDecode = (x, y) => y ?
    (a, b) => x + b.replace(/./g, // Callback to replace each character to be encoded with...
        e => '<' + e.charCodeAt().toString(36) + '<') + y : // ... its number, in base 36, between '<' and '<'
    (c, d) => d.replace(/<(\w+)</g, (a, b) => String.fromCharCode(parseInt(b, 36))); // Callback to decode each portion of string to be decoded
console.log('++just got up++|@&lt;feeling down>@|@@in the dumps@@'
    .replace(/@&lt;(.+?)>@/g, encodeWithOrDecode('@&lt;', '>@')).replace(/@@(.+?)@@/g, encodeWithOrDecode('@@', '@@')) // Encodes text to be left raw
    .replace(/\+\+([^\+]+)\+\+/g, (a, b) => b.toUpperCase()) // Capitalises only text to be parsed
    .replace(/@&lt;(.+?)>@/g, encodeWithOrDecode()).replace(/@@(.+?)@@/g, encodeWithOrDecode())); // Decodes text to be left raw

Объяснение

/@&lt;(.+?)>@/g или /@@(.+?)@@/g будут соответствовать всем экземплярам соответствующих разделителей, между которыми есть текст.

  • Левый разделитель (соответственно @&lt; или @@) соответствует буквально
  • Группа захвата соответствует как минимум одному символу, не заканчивающему строку, как можно меньше раз
  • Правый разделитель (соответственно >@ или @@) соответствует буквально

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...