Matching products with optional factors with definite heads

I need to match a products with exactly one factor F, an arbitrary number of factors of head A, and possibly additional inert factors. I'm having trouble writing one pattern that can capture all the following cases.

I tried the following rule (the c term is there for show)

rule1 = Times[ayes___A, F] :> func[Times[ayes], F];

c + F             /. rule1
c + A[x] F        /. rule1
c + A[x] A[y] F   /. rule1
c + d A[x] A[y] F /. rule1
c + F                        (*desired: c + func[1,F]  *)
c + func[A[x], F]            (*correct*)
c + func[A[x] A[y], F]       (*correct*)
c + d func[A[x] A[y], F]     (*correct*)

The first expression failed to properly match, because it doesn't have head Times. Then I tried a second rule with Optional:

rule2 = rule2 = Times[Optional[ayes__A], F] :> func[Times[ayes], F];

(*Input same as above but with /. rule2*)
c + func[1,F]                (*correct*)
c + func[A[x], F]            (*correct*)
c + func[A[x] A[y], F]       (*correct*)
c + d A[x] A[y] func[1, F]   (*desired: c + d func[A[x] A[y], F] *)

This time the fourth expression failed to match because of the extra factor. So now I try a third rule to accommodate that extra factor:

rule3 = Times[extra_. Optional[ayes__A], F] :> extra*func[Times[ayes], F]

(*Input same as above but with /. rule3*)
c + func[1,F]              (*correct*)
c + func[A[x], F]          (*correct*)
c + A[y] func[A[x], F]     (*desired: c + func[A[x] A[y], F]*)
c + d A[y] func[A[x], F]   (*desired: c + d func[A[x] A[y], F] *)

Now the pattern matcher got confused probably because of all the optional arguments.

Is there a single pattern that can match all these cases? Since I'm working with potentially large expressions, I would also prefer to avoid using pattern tests (Conditional) for performance reasons.

• Does this get them all? Times[a_. ayes__A, F] | a_. F :> a func[Times[ayes], F]? – march Mar 20 '16 at 22:23
• @march It doesn't get the third expression properly, c + A[y] func[A[x], F] – QuantumDot Mar 20 '16 at 22:56
• Right. Missed that one. I still think Alternatives is the way to go, although I'm not sure if it has the same performance hit as using pattern tests. For instance, rule1 = Times[ayes__A, F] | Times[a_ ayes__A, F] | a_. F :> a func[Times[ayes], F];. – march Mar 20 '16 at 22:59

ReplaceAll can use a list of rules.

Here the first rule in the list addresses Times and F. The second rule (which is only invoked if the first rule is not used) addresses Plus and F.

rule = {Times[F, extra_., ayes__A] ->  extra func[Times[ayes], F],
c_ + F -> c + func[1, F]}

Now

c + F             /. rule
c + A[x] F        /. rule
c + A[x] A[y] F   /. rule
c + d A[x] A[y] F /. rule

produces

c + func[1, F]
c + func[A[x], F]
c + A[x] func[A[y], F]
c + d func[A[x], A[y], F]