# Formatting text through pattern matching

I am trying to format some text based on some patterns.

Clear[highlight];
SetAttributes[highlight, HoldAll];
highlight[pattern_, style_] :=
s_String :> Row[List @@ StringReplace[s, t : pattern :> style[t]]]


This works fine and dandy if a match is found:

"foo bar baz" /. highlight["foo", Style[#, Red] &]


But doesn't if no match is found:

"fu bar baz" /. highlight["foo", Style[#, Red] &]


Row["fu bar baz"]

The failure to match has left us with an ugly Row. I'm having a bit of trouble fixing this case, perhaps you can help?

-

Here is what I'd do:

Clear[highlight];
SetAttributes[highlight, HoldAll];
highlight[pattern_, style_] :=
s_String :>
With[{replaced = StringReplace[s, t : pattern :> style[t]]},
Row[List @@ replaced] /; replaced =!= s]


What happens here is that I use the variable replaced shared between the body of With and the condition. This is a very handy construct in many cases. It has the effect that while we do some computations in the body, at the end the rule may be considered not matched by the pattern-matcher. This is often convenient in cases when the fact of the match requires some computations, to be established.

This form has also a global version, which has many applications as well, inlcuding the Trott-Strzebonski in-place evaluation technique, discussed e.g. here.

-
Sorry, could you say that your method for highlight is better or more efficient than the approach of Mr. Wizard? For me, it seems that they are pretty similar. Your usage of With has any implication to help me to solve my question here?: mathematica.stackexchange.com/q/95912/7251 Thanks – jonaprieto Oct 31 '15 at 6:08
@d555 My version is different from Mr.Wizard's in that it doesn't transform the expression in any way if there is now match. His version seems to always wrap the transformed string into Row. – Leonid Shifrin Oct 31 '15 at 10:56

Update: I believe the best way is to use Apply, exploiting the behavior that f @@ x yields x when x is atomic (like a String). Therefore with the code below a raw string remains a string, whereas a StringExpression is converted to a Row.

Clear[highlight];
SetAttributes[highlight, HoldAll];

highlight[pattern_, style_] :=
s_String :> (Row[{##}] & @@ StringReplace[s, t : pattern :> style[t]])


Test:

{"foo bar baz", "fu bar baz"} /.
highlight["foo", Style[#, Red] &]


-