仅匹配“儿童"的模式某些元素的 [英] Pattern to match only "children" of certain elements

查看:31
本文介绍了仅匹配“儿童"的模式某些元素的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望能够有一个模式只匹配那些(或者:不是)某些其他元素的子元素的表达式.

I would like to be able to have a pattern that matches only expressions that are (alternately: are not) children of certain other elements.

例如,匹配所有不在 Graphics 对象内的 List 的模式:

For example, a pattern to match all Lists not within a Graphics object:

{ {1,2,3}, Graphics[Line[{{1,2},{3,4}}]] }

此模式将匹配 {1,2,3} 但不匹配 {{1,2},{3,4}}.

This pattern would match {1,2,3} but not {{1,2},{3,4}}.

有相对简单的方法来提取符合这些条件的表达式,但模式不仅用于提取,还用于替换,这是我在这里的主要用例(全部替换).

There are relatively easy ways to extract expressions matching these criteria, but patterns are not only for extraction, but also for replacement, which is my main use case here (ReplaceAll).

你知道有什么简单、简洁和通用的方法来做到这一点吗?

Do you know of any easy, concise, and general ways to do this?

是否可以只用模式来做到这一点?

推荐答案

我将提出一个基于表达式预处理和使用规则的操作软重新定义的解决方案,而不是规则本身.代码如下:

I will propose a solution based on expression pre-processing and soft redefinitions of operations using rules, rather than rules themselves. Here is the code:

ClearAll[matchChildren, exceptChildren];
Module[{h, preprocess},
  preprocess[expr_, parentPtrn_, lhs_, match : (True | False)] :=
     Module[{pos, ptrnPos, lhsPos},
       ptrnPos = Position[expr, parentPtrn];
       lhsPos = Position[expr, lhs];
       pos = Cases[lhsPos, {Alternatives @@ PatternSequence @@@ ptrnPos, __}];
       If[! match,pos = Complement[Position[expr, _, Infinity, Heads -> False], pos]];
       MapAt[h, expr, pos]];

  matchChildren /: 
    fun_[expr_, matchChildren[parentPtrn_, lhs : Except[_Rule | _RuleDelayed]],
    args___] :=
       fun[preprocess[expr, parentPtrn, lhs, True], h[lhs], args] //. 
           h[x_] :> x;

  matchChildren /: 
    fun_[expr_, matchChildren[parentPtrn_, lhs_ :> rhs_], args___] :=
       fun[preprocess[expr, parentPtrn, lhs, True], h[lhs] :> rhs, args] //. 
           h[x_] :> x;

  exceptChildren /: 
   fun_[expr_,exceptChildren[parentPtrn_, lhs : Except[_Rule | _RuleDelayed]], 
   args___] :=
       fun[preprocess[expr, parentPtrn, lhs, False], h[lhs], args] //. 
           h[x_] :> x;

  exceptChildren /: 
   fun_[expr_, exceptChildren[parentPtrn_, lhs_ :> rhs_], args___] :=
       fun[preprocess[expr, parentPtrn, lhs, False], h[lhs] :> rhs, args] //. 
          h[x_] :> x;
]

有关实现思路及其工作原理的一些详细信息.这个想法是,为了限制应该匹配的模式,我们可以将这个模式包装在某个头部(比如 h),并且还包装所有与原始模式匹配但同时存在(或不存在)的元素是)在同一头部 h 中的其他元素(匹配父"模式)中.这可以用于通用的子"模式.从技术上讲,使之成为可能的一件事是规则应用程序的侵入性(和函数参数传递,在这方面具有相同的语义).这允许我们采用像 x_List:>f[x] 这样的规则,通过通用模式 lhs_:>rhs_ 匹配,并将其更改为 h[x_List]:>f[x],一般使用h[lhs]:>rhs.这很重要,因为 RuleDelayed 是一个作用域构造,只有另一个 RuleDelayed(或函数参数传递)的侵入性允许我们进行必要的作用域手术.在某种程度上,这是一个建设性使用相同效果的例子,导致 Mathematica 中的函数抽象漏洞.这里的另一个技术细节是使用 UpValues 以软"方式重载使用规则(CasesReplaceAll 等)的函数,无需向它们添加任何规则.同时,这里的 UpValues 允许代码具有通用性——一个代码服务于许多使用模式和规则的功能.最后,我使用Module变量作为封装机制,隐藏辅助头h和函数preprocess.这通常是一种非常方便的方法,可以在小于包但大于单个函数的规模上实现函数和数据的封装.

A few details on implementation ideas, and how it works. The idea is that, in order to restrict the pattern that should match, we may wrap this pattern in some head (say h), and also wrap all elements matching the original pattern but also being (or not being) within some other element (matching the "parent" pattern) in the same head h. This can be done for generic "child" pattern. Technically, one thing that makes it possible is the intrusive nature of rule application (and function parameter-passing, which have the same semantics in this respect). This allows one to take the rule like x_List:>f[x], matched by generic pattern lhs_:>rhs_, and change it to h[x_List]:>f[x], generically by using h[lhs]:>rhs. This is non-trivial because RuleDelayed is a scoping construct, and only the intrusiveness of another RuleDelayed (or, function parameter-passing) allows us to do the necessary scope surgery. In a way, this is an example of constructive use of the same effect that leads to the leaky functional abstraction in Mathematica. Another technical detail here is the use of UpValues to overload functions that use rules (Cases, ReplaceAll, etc) in the "soft" way, without adding any rules to them. At the same time, UpValues here allow the code to be universal - one code serves many functions that use patterns and rules. Finally, I am using the Module variables as a mechanism for encapsulation, to hide the auxiliary head h and function preprocess. This is a generally very handy way to achieve encapsulation of both functions and data on the scale smaller than a package but larger than a single function.

以下是一些示例:

In[171]:= expr = {{1,2,3},Graphics[Line[{{1,2},{3,4}}]]};

In[168]:= expr/.matchChildren[_Graphics,x_List:>f[x]]//FullForm
Out[168]//FullForm= List[List[1,2,3],Graphics[Line[f[List[List[1,2],List[3,4]]]]]]

In[172]:= expr/.matchChildren[_Graphics,x:{__Integer}:>f[x]]//FullForm
Out[172]//FullForm= List[List[1,2,3],Graphics[Line[List[f[List[1,2]],f[List[3,4]]]]]]

In[173]:= expr/.exceptChildren[_Graphics,x_List:>f[x]]//FullForm
Out[173]//FullForm= List[f[List[1,2,3]],Graphics[Line[List[List[1,2],List[3,4]]]]]

In[174]:= expr = (Tan[p]*Cot[p+q])*(Sin[Pi n]+Cos[Pi m])*(Tan[q]+Cot[q]);

In[175]:= expr/.matchChildren[_Plus,x_Tan:>f[x]]
Out[175]= Cot[p+q] (Cot[q]+f[Tan[q]]) (Cos[m \[Pi]]+Sin[n \[Pi]]) Tan[p]

In[176]:= expr/.exceptChildren[_Plus,x_Tan:>f[x]]
Out[176]= Cot[p+q] f[Tan[p]] (Cos[m \[Pi]]+Sin[n \[Pi]]) (Cot[q]+Tan[q])

In[177]:= Cases[expr,matchChildren[_Plus,x_Tan:>f[x]],Infinity]
Out[177]= {f[Tan[q]]}

In[178]:= Cases[expr,exceptChildren[_Plus,x_Tan:>f[x]],Infinity]
Out[178]= {f[Tan[p]]}

In[179]:= Cases[expr,matchChildren[_Plus,x_Tan],Infinity]
Out[179]= {Tan[q]}

In[180]:= Cases[expr,matchChildren[_Plus,x_Tan],Infinity]
Out[180]= {Tan[q]}

它预计适用于格式为 fun[expr_,rule_,otherArgs___] 的大多数函数.特别是,那些包括 Cases,DeleteCases, Replace, ReplaceAll,ReplaceRepeated.我没有概括到规则列表,但这应该很容易做到.在一些微妙的情况下,它可能无法正常工作,例如具有非平凡的头部和头部的模式匹配.

It is expected to work with most functions which have the format fun[expr_,rule_,otherArgs___]. In particular, those include Cases,DeleteCases, Replace, ReplaceAll,ReplaceRepeated. I did not generalize to lists of rules, but this should be easy to do. It may not work properly in some subtle cases, e.g. with non-trivial heads and pattern-matching on heads.

这篇关于仅匹配“儿童"的模式某些元素的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆