Перетворити вираз у нотацію Panfix


19

Я переглядав esolangs і переглядав цю мову: https://github.com/catseye/Quylthulg .

Цікава річ у цій мові - це те, що вона не використовує префікса, постфікса чи інфіксацію, вона використовує всі три з них , називаючи це позначенням "panfix".

Ось приклад. Щоб уявити нормальний Інфікси 1+2в panfix, вона стає: +1+2+. Зауважте, як оператор є і перед, і між операндами, між ними та після них. Інший приклад - (1+2)*3. Це стає *+1+2+*3*. Зауважте ще раз, як *у всіх трьох місцях щодо операндів +1+2+та 3.

Змагання

Як ви вже здогадалися, ваше завдання в цьому виклику - перетворити вираз з інфіксації в панфікс.

Кілька роз'яснень:

  • Ви повинні мати справу лише з чотирма основними операціями: +-*/
  • Вам не доведеться мати справу з одинарними версіями, лише бінарними
  • Ви повинні мати справу з дужками
  • Припустимо нормальні правила пріоритетності */тодішньої +-та лівої асоціативності для всіх них.
  • Числа будуть невід’ємними цілими числами
  • При необхідності ви можете мати пробіли і в вході, і у виході

Випробування

1+2  ->  +1+2+
1+2+3  ->  ++1+2++3+
(1+2)*3  ->  *+1+2+*3*
10/2*5  ->  */10/2/*5*
(5+3)*((9+18)/4-1)  ->  *+5+3+*-/+9+18+/4/-1-*

Це , тому найкоротший код у байтах виграє!

Відповіді:


3

JavaScript (ES6), 160 байт

f=(s,t=s.replace(/[*-/]/g,"'$&'"),u=t.replace(/^(.*?)([*-9]+)'([*/])'([*-9]+)|([*-9]+)'([+-])'([*-9]+)|\(([*-9]+)\)/,"$1$3$2$3$4$3$6$5$6$7$6$8"))=>t==u?t:f(s,u)

Працює, цитуючи всіх операторів (що надає їм коди символів раніше *), потім шукає доступні '*'або '/'операції, '+'або '-'операції або ()s, і замінюючи першого своїм позначенням panfix. Приклад:

(5+3)*((9+18)/4-1)
(5'+'3)'*'((9'+'18)'/'4'-'1)
(+5+3+)'*'((9'+'18)'/'4'-'1)
+5+3+'*'((9'+'18)'/'4'-'1)
+5+3+'*'((+9+18+)'/'4'-'1)
+5+3+'*'(+9+18+'/'4'-'1)
+5+3+'*'(/+9+18+/4/'-'1)
+5+3+'*'(-/+9+18+/4/-1-)
+5+3+'*'-/+9+18+/4/-1-
*+5+3+*-/+9+18+/4/-1-*

3

JavaScript (ES6), 285 282 281 267 251 243 241 238 234 232 231 байт

~ 15 байт завдяки Нілу .

f=(I,E=I.match(/\d+|./g),i=0)=>(J=T=>T.map?T.map(J).join``:T)((R=(H,l=(P=_=>(t=E[i++])<")"?R(0):t)(),C,F)=>{for(;(C=P())>")"&&(q=C>"*"&&C<"/")*H-1;)F=q+H?l=[C,l,C,P(),C]:F?l[3]=[C,l[3],C,R(1),C]:l=R(1,l,i--)
i-=C>")"
return l})(0))

У JavaScript це трохи складніше, ніж у Mathematica. Це, в основному, надспеціалізований аналізатор пріоритетності операторів з гольфу .

Викликає переповнення стека на недійсних введеннях.

Демо

Безумовно

convert = input => {
  tokens = input.match(/\d+|./g);
  i = 0;
  parse_token = () => (token = tokens[i++]) == "(" ? parse_tree(false) : token;
  parse_tree = (mul_div_mode, left = parse_token()) => {
    while ((oper = parse_token()) != ")" && !((is_plus_minus = oper == "+" || oper == "-") && mul_div_mode)) {
      if (is_plus_minus || mul_div_mode)
        left = [oper, left, oper, parse_token(), oper];
      else if (non_first)
        left[3] = [oper, left[3], oper, parse_tree(true), oper];
      else
        left = parse_tree(true, left, i--);
      non_first = true;
    }
    if (oper != ")")
      i--;
    return left;
  };
  format_tree = tree => tree.map ? tree.map(format_tree).join("") : tree;
  return format_tree(parse_tree(false));
}

S.split``Це повинно бути [...S], хоча це насправді може допомогти узгодитись /\d+|./gнаперед та працювати на цьому.
Ніл

@Neil Дякую Я розберуся в цьому.
PurkkaKoodari

2

Математика, 203 195 байт

Це, мабуть, менш ефективно, але, здається, справляється із цією справою.

Function[f,ReleaseHold[(Inactivate@f/._[Plus][a_,b_/;b<0]:>a~"-"~-b//Activate@*Hold)//.a_/b_:>a~"/"~b/.{a_Integer:>ToString@a,Plus:>"+",Times:>"*"}]//.a_String~b_~c_String:>b<>a<>b<>c<>b,HoldAll]

Це анонімна функція, яка приймає фактичний вираз і повертає рядок із позначенням panfix. Mathematica розбирає пріоритет операторів у синтаксичному аналізі, а не час оцінювання, тому введення має бути автоматично правильним. Принаймні тестові випадки працюють так, як очікувалося.

Пояснення: Досить просто інтерпретувати весь вираз як дерево, наприклад:

дерево

На цьому етапі оператори (кожен вузол, який не є аркушем) вже не є операторами, вони фактично перетворені на такі рядки, як "+". Цілі числа також передаються рядкам. Потім правило повторної заміни перетворює кожен вузол, у якого є рівно два крила, у панфікс parent-leaf1-parent-leaf2-parent. Після деяких ітерацій дерево зменшується до однієї струни.

Основна втрата в кількості байтів полягає в тому, що Mathematica інтерпретує

5 - 4 -> 5 + (-4)
9 / 3 -> 9 * (3^(-1))

І це відбувається також під час розбору.

Гольф трохи вниз, оскільки шаблон a_/b_також трактується як a_ * (b_)^(-1). Також деякі незначні оптимізації в інших місцях.


1

Пролог, 87 байт

x(T)-->{T=..[O,A,B]}->[O],x(A),[O],x(B),[O];[T].
p:-read(T),x(T,L,[]),maplist(write,L).

Це функція (здебільшого тому, що написання повної програми має кошмарний рівень котлоагрегату в Prolog; як правило, навіть якщо ви скомпілювати програму, вона виробляє REPL при запуску), під назвою p. Він приймає вхід з stdin та виводить на stdout. Зауважте, що вам потрібно додати період до введення, що є невдалим наслідком того, як працюють вхідні програми Prolog (вони використовують періоди у введенні так само, як і інші мови використовують нові рядки); що може або не може дискваліфікувати відповідь.

Пояснення

Арифметичні оператори в Prolog зазвичай трактуються як кортежні конструктори . Однак вони дотримуються тих самих правил пріоритету, що і фактичні арифметичні оператори, на яких вони засновані; ви можете сформувати кортежі з інфіксованими позначеннями +і -зв’язати менш щільно, ніж *і/ , з перевагою, зробленим зліва направо в межах групи. Саме це і задається питанням; таким чином, ми можемо прочитати цілий вкладений кортеж із вхідних даних, і він вже має правильну структуру. Ось що і pробить.

Далі нам потрібно перетворити його на позначення panfix. xперетворює вхідні дані в panfixed список конструкторів і цілих чисел, і може бути прочитана як англійське пропозицію майже прямо: « xз T: якщо Tце кортеж з конструктором Oі аргументами A, B, то O, xпро A, O, xпро B, O, інакше T». Нарешті, нам просто потрібно надрукувати список без розділювачів (тобто використовувати maplistдзвінки writeпо кожному елементу списку).

Я використовував SWI-Prolog для тестування цього, оскільки моя версія GNU Prolog ще не була maplist(мабуть, вона була додана до нової версії), але вона, як правило, має бути досить портативною між реалізаціями Prolog.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.