Panfix到括号中的括号


16

Quylthulg是Chris Pressey 编写的一种语言,它试图通过使用panfix来解决中缀表示法的问题:

像postfix一样,panfix不需要部署神秘的设计(例如括号)来覆盖默认的运算符优先级。同时,panfix允许以与infix相同的顺序和方式来指定术语,这对于已经习惯infix的人来说无疑是一种自然而直观的表示法。


如何获得前缀表示法的便利性以及前缀或后缀的明确性?当然,全部使用这三个!

=y=+*3*x*+1+=

更正式,更+是运营商,并ab是表达式。然后(a+b)是一个有效的(带括号)中缀表达式,该表达式的panfix表示为+a+b+,其中并置表示串联。

您的目标是获取一个panfix字符串并将其转换为带括号的后缀:

(y=((3*x)+1))

为简单起见,我们将进行以下更改:

  • 运算符只能由两个唯一的字符组成(您可以选择任何一个,但是在这里我将使用*+)。
  • 只有一个文字,它由另一个不同的字符组成(您可以选择任何一个,但在这里我将使用_)。
  • 输入将是格式正确的panfix表达式。

对于复杂性,我们将进行以下更改:

  • 运算符可以包含任意数量字符,而不仅仅是一个。

这使挑战变得更加棘手,因为您无需确定字符串的其余部分就不必确定给定的操作符子字符串的分区方式。

这是挑战的参考实现,由@ user202729提供。

测试用例

format: input -> output
+*+_*+_*+++_+*+_*+_*+++ -> ((_*+_)+(_+(_*+_)))
**++*+***++_+_++_+*++*+***_*++*+*****_**_*_*** -> ((((_+_)+_)*++*+***_)*(_*(_*_)))
***_**_***_* -> ((_**_)*_)
+_+_+ -> (_+_)
*+*+++**+***+++++_*+*+++**+***+++++_*+*+++**+***+++++ -> (_*+*+++**+***+++++_)
*++++*+*_*_*+*+++****+_++****+_++****++*+*+++_*+++ -> (((_*_)+*+(_++****+_))*+++_)
+**+_*+_*+*_*+*_*+*_+*_+**+ -> (((_*+_)*_)+(_*(_+*_)))
+**+++++_+++++_+++++*_*+*+_++++++_+++++_+++++++* -> (((_+++++_)*_)+*(_+(_+++++_)))
+*+*+_+*+_+*+*_*+*_*+*+_+*+_+*+*+ -> (((_+*+_)*_)+(_*(_+*+_)))
**_**_**_*_****_* -> ((_*(_*(_*_)))*_)

我使用此程序生成了针对此挑战的中缀字符串(转换为panfix很简单,但不可逆转)。




6
建议的测试用例:**_**_**_*_****_*。我测试过的答案都没有通过这个答案。
Nitrodon

1
我的输出中可以有多余的空格(_ + _)吗?
Ton Hospel '18

2
@TonHospel当然。
硕果累累'18

Answers:


6

Prolog(SWI)194163字节

使用此提示0'保存了多达31个字节!

[C|T]/O/R:-C\=x,(T/P/R,concat(C,P,O);O=C,R=T).
[x|R]-x-R.
L-X-R:-L/O/A,A-Y-B,B/O/C,C-Z-D,D/O/R,atomics_to_string(['(',Y,O,Z,')'],X).
X^P:-string_chars(X,L),L-P-[].

运算符^的左参数为一个包含panfix表达式的字符串,其右参数为一个包含相应括号内的infix表达式的字符串。它x用作代替的文字_

在线尝试!

说明

由于Prolog是一种声明性语言,因此我们仅需描述panfix和带括号的表达式之间的关系。

解释使用了这个略微偏离版本的版本:

oper([C|T],O,R) :- C\=x, oper(T,P,R), concat(C,P,O).
oper([C|T],C,T).

expr([x|R],x,R).
expr(L,X,R) :- oper(L,O,A), expr(A,Y,B), oper(B,O,C), expr(C,Z,D), oper(D,O,R),
               atomics_to_string(['(',Y,O,Z,')'],X).

parenthesize(X,P) :- string_chars(X,L), expr(L,P,[]).

我们的主要产品是parenthesize,它以Panfix表达式X作为字符串,并以字符串形式发送相应的带括号的中缀表达式P。它用于string_chars将输入字符串转换为字符列表,然后将其简单地传递给expr

expr接收一个字符列表L,解析它找到的第一个panfix表达式L,并发出括号中的等价X字符和其余字符列表R。有两种可能的表达式:

  • 如果的第一个字符Lx,则表达式为x,其余为后面的所有内容x
  • 否则,解析一个运算符O(见oper下文);解析表达式Y; O再次解析;解析另一个表达式Z; 并O第三次解析。其余的是的第三个实例之后的所有内容O。表达是连接的结果YO以及Z,用括号括起,为一个字符串。

oper接受一个字符列表,其中第一个字符为C,其余字符为T;它解析一个运算符(即一个或多个运算符),并发出该运算符O和其余字符列表R。要形成运算符,字符C必须不是x;;还可以

  • 操作员P必须T与其他人保持一致R; 在这种情况下,O是的级联CP; 要么,
  • O是单个字符C; 在这种情况下,Ris T

一个可行的例子

让我们以输入+*+x+x++*x+*为例。

  • 我们想从中解析一个表达式+*+x+x++*x+*。它不是以开头的x,所以我们从头开始解析一个运算符。
  • oper将解析尽可能多的运算符,因此我们尝试+*+
    • 接下来,我们从中解析一个表达式x+x++*x+*。这一定是x
    • 现在,我们尝试分析同一个运营商,+*++x++*x+*。但是,这失败了
  • 因此,我们回溯并尝试解析运算符+*
    • 我们从中解析一个表达式+x+x++*x+*。它不是以开头的x,因此我们需要解析一个运算符。
    • 唯一的可能性是+
    • 现在从中解析一个子表达式x+x++*x+*。这一定是x
    • 现在+从中再次解析+x++*x+*
    • 现在,从中解析另一个子表达式x++*x+*。这一定是x
    • 最后,+再次从解析++*x+*
    • 该表达式已成功解析。我们返回字符串(x+x)
  • 回到上一个递归级别,我们+*再次从解析操作符+*x+*
  • 现在,从中解析另一个子表达式x+*。这一定是x
  • 最后,+*再次从解析+*
  • 该表达式已成功解析。我们返回字符串((x+x)+*x)

由于没有更多的字符了,我们已经成功翻译了该表达式。


4

Perl,78 60 58 57 50字节

包括+1用于p

用途1+2*(或实际上任何数字适用于任何运营商)

perl -pe 's/\b((\d+)((?1)|_)\2((?3))\2)\b/($3 $2 $4)/&&redo' <<< 22_22_22_2_2222_2

为了方便地与给定的示例进行测试,您可以使用它为您完成翻译和空格删除:

perl -pe 'y/+*/12/;s/\b((\d+)((?1)|_)\2((?3))\2)\b/($3 $2 $4)/&&redo;y/ //d;y/12/+*/' <<< "**_**_**_*_****_*"

3

干净200个 192 189字节

import StdEnv,Text
f"_"=["_"]
f l=["("+a+p+b+")"\\p<-[l%(0,i)\\i<-[0..indexOf"_"l]|endsWith(l%(0,i))l],t<-[tl(init(split p l))],n<-indexList t,a<-f(join p(take n t))&b<-f(join p(drop n t))]

在线尝试!

定义函数f,采用String,并返回[String]内部包含结果的单例。

一些简单的东西:

  • 不使用正则表达式
  • 运算符,任何字符均可使用_

3

视网膜0.8.2,138字节

.+
($&)
+`\((\d+)(_|((?<i>(?<i>\d+))|_(?<-i>\k<i>)+)+(?(i)(?!)))\1(_|((?<i>(?<i>\d+))|_(?<-i>\k<i>)+)+(?(i)(?!)))\1\)
(($2)$1($4))
\(_\)
_

在线尝试!链接包括更快的测试用例。说明:正则表达式引擎使用回溯将字符串分成多个令牌,然后将其推入i平衡组或从平衡组中弹出。在开始时,总是有至少一个运算符被推到第一个变量之前。变量后,至少弹出一个运算符,此时,强制执行运算符运行或另一个变量合法。操作员会被重复推送到组中,以便可以正确弹出。例:

Input           Stack
Push *          * *
Push *++*+***   * * *++*+*** *++*+***
Push +          * * *++*+*** *++*+*** + +
Push +          * * *++*+*** *++*+*** + + + +
Variable _
Pop +           * * *++*+*** *++*+*** + + +
Variable _
Pop +           * * *++*+*** *++*+*** + +
Pop +           * * *++*+*** *++*+*** +
Variable _
Pop +           * * *++*+*** *++*+***
Pop *++*+***    * * *++*+***
Variable _
Pop *++*+***    * *
Pop *           *
Push *          * * *
Variable _
Pop *           * *
Push *          * * * *
Variable _
Pop *           * * *
Variable _
Pop *           * *
Pop *           *
Pop *

不幸的是,这无助于我们捕获结果并将其括起来,因此外部运算符是手动匹配的。方括号是从外到内添加的,因此第一个阶段将整个表达式包装在方括号中,而最后一个阶段将其扩展到变量后将其删除。


1
这也对失败**_**_**_*_****_*
user202729'2

@ user202729现在工作吗?
尼尔

@Neil现在正在工作,是的。
世纪

1

哈斯克尔167个 166字节

head.e
e('_':r)=["_",r]
e(x:r)=[x]%r
e _=[]
o%t@(c:r)|[x,u]<-e t,n<-length o,[y,v]<-e$drop n u,all((==o).take n)[u,v]=['(':x++o++y++")",drop n v]|p<-o++[c]=p%r
o%_=[]

在线尝试!用法示例:head.e "**_**_**_*_****_*"yields ((_*(_*(_*_)))*_)。除之外的所有字符都_被解释为运算符,_其本身表示一个标识符。


0

Python 3,226个字节

from re import*
P=r'([*+]+)'+r'(\(.+?\)|_)\1'*2;R=lambda i,J=lambda i,o:i[:o]+sub(P,lambda o:'('+o[2]+o[1]+o[3]+')',i[o:],1),s=search:s(P,i)and R([J(i,o)for o in range(len(i))if s(P,J(i,o))or J(i,o)[0]+J(i,o)[-1]=='()'][0])or i

定义一个名为的匿名函数R

在线尝试!


请注意,您可以使用除_*+; 以外的任何字符。这些只是示例中使用的内容。您可能可以使用它来打高尔夫球您的正则表达式(例如,使用\d代替[*+])。
Esolanging Fruit '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.