нужна помощь с регулярными выражениями js
Мне надо оборачивать выражения рядом с которыми стоит восклицательный знак в функцию факториал.
Например:
5! -> factorial(5)
Но при этом:
5!! -> factorial( factorial(5) )
Вообще выражение может быть любой сложности, например:
5 + 3 - ((44 - 38)! - 3)!
Я долго думал как реализовать это с помощью регулярный выражений, и не смог. Но не обязательно использовать регулярные выражения. Если есть идеи, как реализовать это без регулярок, можете писать.
Ответы (1 шт):
В целом, я поддерживаю комментарии под вопросом, что это задача разбора грамматики. Но так как в вопросе есть пункт: Если есть идеи, как реализовать это без регулярок, можете писать., напишу вариант как это можно сделать относительно просто, если не предполагаются выражения больше n!!
Принцип алгоритма:
пройти с конца по строке, найти ее диапазоны к которым применяется факториалы. например [[8,24], [9, 18], ...] где 8 - начало выражения, 24 - конец перед символом
!далее для безболезненной вставки (чтобы не потерять диапазоны) строка бьется на буквы (массив), теперь вставки не будут влиять на данные о диапазонах.
делаются вставки с помощью
spliceдля каждого диапазонамассив объединяется в строку - выводится результат
function getStart(s, index){
let brackets = 0
for(let i=index-1; i >= 0; i--){
if (s[i] === ')') brackets++
if (brackets && s[i] === '(') brackets--
// возвращаем позицию открывающей скобки
if (brackets === 0 && s[i] !== '!' ) return i
}
}
function replaceFactorial(s, ranges){
if (ranges.length === 0) return s
let range = null
let result = s.split('')
while(range = ranges.shift()){
if (s[range[1]-1] === ')'){ // были скобки
result.splice(range[0] , 1, 'factorial(')
result.splice(range[1], 1 )
} else if (s[range[1]+1] === '!'){ // двойной факториал
result.splice(range[0] , 0, 'factorial(')
result.splice(range[1] + 2, 1 , ')' )
} else { // выражение было без скобок, например: 5!!
result.splice(range[0] , 0, 'factorial(')
result.splice(range[1] + 1, 1, ')' )
}
}
return result.join('')
}
function transform(s){
let ranges = []
for(let i=s.length-1; i >= 0; i--){
if(s[i] === '!'){
ranges.push([getStart(s, i), i])
}
}
return replaceFactorial(s, ranges)
}
let test ='5! + 3 - ((44 - 38)! - 3)! + 7!!'
console.log(test)
console.log(transform(test))