8
$\begingroup$

I have a list of strings list. I am trying to get rid of some elements that match string pattern patt:

list /. x_ /; StringMatchQ[x, patt] -> Nothing

I get the result I want but I also get an error:

StringMatchQ::strse: String or list of strings expected at position 1 in StringMatchQ[List, patt].

This happens because ReplaceAll also evaluates the condition on the Head of list. How can I get the result I want but prevent the error?

$\endgroup$
  • $\begingroup$ Proposed duplicate: (7688) Also related: (17497) $\endgroup$ – Mr.Wizard Aug 28 '16 at 7:00
  • $\begingroup$ amrods, thanks for the Accept. Do you feel that your question is a duplicate of 7688 linked above? If so we should mark it as such. $\endgroup$ – Mr.Wizard Aug 29 '16 at 3:50
  • $\begingroup$ I don't think it's a duplicate. $\endgroup$ – amrods Aug 29 '16 at 4:25
  • $\begingroup$ You could use Quiet also. $\endgroup$ – Algohi Aug 31 '16 at 0:24
7
$\begingroup$

IMHO the simplest solution is to restrict the pattern on the left side of Condition, i.e. change x_ to x_String:

patt = ___ ~~ "a" ~~ ___;

{"good", "bad"} /. x_String /; StringMatchQ[x, patt] -> Sequence[]

(*  {"good"}  *)

You can instead use Replace as indicated in other answers, however:

  • the optimal levelspec to target atomic elements like Strings is {-1}
  • The default Heads value False is what prevents List from being pattern matched.

Please understand that Replace does not work the same as ReplaceAll, regardless of levelspec, because it uses a different traversal order. See:

$\endgroup$
6
$\begingroup$

Solution

You could use Replace (ReplaceAll is effectively the same as using All or {0, Infinity} as levelspec in Replace).

Example

list = {"a", "b", "c"};
patt = "a";
Replace[list, x_ /; StringMatchQ[x, patt] -> Nothing, {1, Infinity}]

(* {"b", "c"} *)

Alternative Solution

In your case, since you are replacing something with Nothing, you could simply use DeleteCases:

DeleteCases[list, patt, All]

(* {"b", "c"} *)
$\endgroup$
  • $\begingroup$ Change the levelspec as needed. (If your list is level 1, then {1} would be enough) $\endgroup$ – JungHwan Min Aug 28 '16 at 3:58
6
$\begingroup$

Use Replace instead of ReplaceAll.

ReplaceAll[{"x", "y", "z"}, x_ /; StringMatchQ[x, "x"] -> Nothing]

StringMatchQ::strse: String or list of strings expected at position 1 in StringMatchQ[List,x].

(* {"y", "z"} *)

as in the question. In contrast,

Replace[{"x", "y", "z"}, x_ /; StringMatchQ[x, "x"] -> Nothing, {1}]

yields the same answer but without the error message.

Correction

For nested Lists, it appears necessary to restrict patt to be a String, as noted by Mr.Wizard.

Replace[{"x", "y", "z", {"a", "x", {"b", "x"}}}, 
    x_String /; StringMatchQ[x, "x"] -> Nothing, {1, Infinity}]

(* {"y", "z", {"a", {"b"}}} *)
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.