Mr.*_*ard 13 string parsing wolfram-mathematica
在字符串中匹配括号的最有效或最优雅的方法是什么,例如:
"f @ g[h[[i[[j[2], k[[1, m[[1, n[2]]]]]]]]]] // z"
Run Code Online (Sandbox Code Playgroud)
为了识别和替换[[ Part ]]单个字符形式的括号?
我想得到:

其他一切完好无损,例如前缀@和后缀//形式完好无损
对于那些不熟悉的Mathematica语法的解释:
函数使用单个方括号作为参数: func[1, 2, 3]
部分索引使用双方括号:list[[6]]或使用单字符Unicode双括号:list?6?
我的目的是[[ ]]在ASCII文本字符串中标识匹配的表单,并将其替换为Unicode字符? ?
好的,这是另一个答案,有点短:
Clear[replaceDoubleBrackets];
replaceDoubleBrackets[str_String, openSym_String, closeSym_String] :=
Module[{n = 0},
Apply[StringJoin,
Characters[str] /. {"[" :> {"[", ++n},
"]" :> {"]", n--}} //. {left___, {"[", m_}, {"[", mp1_},
middle___, {"]", mp1_}, {"]", m_}, right___} /;
mp1 == m + 1 :> {left, openSym, middle,
closeSym, right} /. {br : "[" | "]", _Integer} :> br]]
Run Code Online (Sandbox Code Playgroud)
例:
In[100]:= replaceDoubleBrackets["f[g[h[[i[[j[2], k[[1, m[[1, n[2]]]]]]]]]]]", "(", ")"]
Out[100]= "f[g[h(i(j[2], k(1, m(1, n[2]))))]]"
Run Code Online (Sandbox Code Playgroud)
编辑
如果您想使用您指示的符号替换双括号,您也可以使用Mathematica内置工具:
Clear[replaceDoubleBracketsAlt];
replaceDoubleBracketsAlt[str_String] :=
StringJoin @@ Cases[ToBoxes@ToExpression[str, InputForm, HoldForm],
_String, Infinity]
In[117]:= replaceDoubleBracketsAlt["f[g[h[[i[[j[2], k[[1, m[[1, n[2]]]]]]]]]]]"]
Out[117]= f[g[h[[i[[j[2],k[[1,m[[1,n[2]]]]]]]]]]]
Run Code Online (Sandbox Code Playgroud)
结果不会在此处正确显示,但它是带有您请求的符号的Unicode字符串.
当我编写第一个解决方案时,我没有注意到你只是想[[用?字符串替换with 而不是表达式.你可以随时使用HoldForm或Defer作为

但我想你已经知道了,你想把表达式作为一个字符串,就像输入一样(ToString@在上面不起作用)
由于到目前为止所有的答案都集中在字符串操作上,我将采用数字方法而不是用字符串进行摔跤,这对我来说更自然.字符代码为[91,]为93.执行以下操作

给出括号的位置作为0/1向量.我已经否定了右括号,只是为了帮助思考过程并在以后使用.
注意:我只检查了91和93的可分性,因为我当然不希望您输入以下任何字符,但如果由于某种原因您选择,您可以AND使用布尔列表轻松地获得上述结果与91或93平等.

由此,Part可以找到第一个双支架对的位置

事实上,在mma中,表达式不是以[并且两个以上[不能连续出现[[[...,这在上面的计算中是隐含的假设.
现在关闭对很难实现,但很容易理解.这个想法如下:
closeBracket,例如i,转到相应的位置openBracket并找到它左边的第一个非零位置(比如说j).doubleCloseBrackets[[i-1]]=closeBracket[[i]]+openBracket[[j]]+doubleOpenBrackets[[j]].doubleCloseBrackets是对方doubleOpenBrackets,并在第一的位置非零Part的]]对.

所以现在我们为第一个开放式括号设置了一组布尔位置.我们只需要更换相应的元素charCode与相当于?同样,与第一接近支架布尔位置,我们在更换相应的元素charCode与等效?.

最后,通过删除已更改的元素旁边的元素,您可以将已修改的字符串[[]]替换为? ?

笔记2:
很多我的MATLAB习惯都在上面的代码中悄悄出现,并且在Mathematica中并不完全是惯用语.但是,我认为逻辑是正确的,并且它有效.我会留给你优化它(我认为你可以废除它Do[])并将其作为一个模块,因为这需要我花费更长的时间.
代码为文本
Clear["Global`*"]
str = "f[g[h[[i[[j[2], k[[1, m[[1, n[2]]]]]]]]]]]";
charCode = ToCharacterCode@str;
openBracket = Boole@Divisible[charCode, First@ToCharacterCode["["]];
closeBracket = -Boole@
Divisible[charCode, First@ToCharacterCode["]"]];
doubleOpenBracket =
Append[Differences@Accumulate[openBracket], 0] openBracket;
posClose = Flatten@Drop[Position[closeBracket, Except@0, {1}], 1];
doubleCloseBracket = ConstantArray[0, Dimensions@doubleOpenBracket];
openBracketDupe = openBracket + doubleOpenBracket;
Do[
tmp = Last@
Flatten@Position[openBracketDupe[[1 ;; i]], Except@0, {1}];
doubleCloseBracket[[i - 1]] =
closeBracket[[i]] + openBracketDupe[[tmp]];
openBracketDupe[[tmp]] = 0;,
{i, posClose}];
changeOpen =
Cases[Range[First@Dimensions@charCode] doubleOpenBracket, Except@0];
changeClosed =
Cases[Range[First@Dimensions@charCode] doubleCloseBracket,
Except@0];
charCode[[changeOpen]] = ToCharacterCode["\[LeftDoubleBracket]"];
charCode[[changeClosed]] = ToCharacterCode["\[RightDoubleBracket]"];
FromCharacterCode@
Delete[Flatten@charCode,
List /@ (Riffle[changeOpen, changeClosed] + 1)]
Run Code Online (Sandbox Code Playgroud)
编辑
TL;博士版本:
我正在无意中解决基本问题,但正则表达式无法计算括号,因此使用堆栈实现。
更长的版本:
我尊敬的同事是正确的,解决这个问题的最佳方法是堆栈实现。如果字符串中存在的数量与 的数量相同,则正则表达式可以分别将[[和更改]]为 和[,但是,如果练习的重点是在匹配中使用文本,那么正则表达式就不是正确的选择。正则表达式不能计算括号的数量,嵌套逻辑对于简单的正则表达式来说太复杂了。因此,简而言之,我相信正则表达式可以用于解决基本要求,即将匹配更改为匹配,但是您实际上应该使用堆栈,因为它可以更轻松地操作结果字符串。][[]][][[]][]
抱歉,我完全错过了mathematica标签!我会把我的答案留在这里,以防万一有人像我一样兴奋并仓促行事。
结束编辑
使用不情愿的量词的正则表达式应该能够逐步确定[[和]]标记在字符串中的位置,并确保仅当 的数量[[等于 的数量时才进行匹配]]。
所需的正则表达式将类似于[[{1}?(?!]])*?]]{1}?,用简单的英语来说是:
[[{1}?,从字符串开头一次前进一个字符,直到[[遇到 的一个实例(?!]])*?如果存在任何不匹配的字符]],则一次一个地处理它们]]{1}?匹配右括号要将双方括号更改为单方括号,请通过在第一个和第三个粒子周围添加括号来识别正则表达式中的组:
([[{1}?)(?!]])*?(]]{1}?)
Run Code Online (Sandbox Code Playgroud)
这允许您选择[[和]]标记,然后将它们替换为[或]。