3
$\begingroup$

Sorry for easy question-- To replace these words as given by the rule:

source = {"C10", "C10T11"};
repl = { "C10" -> "01C10", "C10T11" -> "02C10T11"};

StringReplace doesn't understand that I want the rule to apply only to whole words, apparently:

In[89]:= StringReplace[source, repl]

Out[89]= {"01C10", "01C10T11"}

Where the error in the second element seems to arise by matching the part of the source string, instead of looking for whole word matches. Advice please?

$\endgroup$
3
$\begingroup$

Update: Evidently I missed the thrust of the question. Please feel free to "un-accept" this answer in favor of Mathe172's answer and I'll be able to delete this.

If you are looking for entire string matching only you should as Mathe172 said use ReplaceAll (i.e. source /. repl equiv to ReplaceAll[source,repl]), not StringReplace, whose entire purpose is substring replace.

For entire string replacement it will be much faster to use ReplaceAll, and you won't have to worry about sort order.

I misunderstood the question to be dealing with frustration at sub-expressions getting matched first, not sub-expressions getting matched at all.


orig answer:

What's happening is that your short string is getting replaced first because of order of your replacement rules.

You can do the following:

sortedReplaceLongestFirst = Sort[repl, ! OrderedQ[StringLength[First[#]] & /@ {#1, #2}] &];

yielding:

{"C10T11" -> "02C10T11", "C10" -> "01C10"}

Applying:

StringReplace[source, sortedReplaceLongestFirst ]

gives,

{"01C10", "02C10T11"}

$\endgroup$
  • $\begingroup$ Thanks! ... a bit more complicated than I thought, and I actually have a long list of words to replace... $\endgroup$ – radford_et_al Aug 18 '17 at 14:55
  • $\begingroup$ Yes. If there is a chance that you are pattern matching on substrings you want to do a sort such that your rules are ranked from longest matching substring to shortest. Maybe this update is a little clearer. $\endgroup$ – John Joseph M. Carrasco Aug 18 '17 at 14:57
  • 1
    $\begingroup$ Reverse@SortBy[repl, StringLength@*First] should do the same thing as your sorting expression $\endgroup$ – Lukas Lang Aug 18 '17 at 15:04
  • $\begingroup$ Also, I don't think that this is what the question asks for - if you remove the second replacement rule, this approach still incorrectly replaces parts of the second string. $\endgroup$ – Lukas Lang Aug 18 '17 at 15:08
  • $\begingroup$ So far the sorting is giving the answer I was looking for, sorry if question is unclear. $\endgroup$ – radford_et_al Aug 18 '17 at 15:12
8
$\begingroup$

If you really only want to replace full words, just use ReplaceAll:

 source /. repl
 Out[1]:=  {"01C10", "02C10T11"}
$\endgroup$
  • $\begingroup$ You're absolutely right, I misread the point of the question. (+1) $\endgroup$ – John Joseph M. Carrasco Aug 18 '17 at 15:09
4
$\begingroup$

I would use ReplaceAll as in @Mathe172's answer. But, if you have to use StringReplace, you can change rpl to include information that you want the rule to apply only to whole words:

repl2 = WordBoundary ~~ # ~~ WordBoundary -> #2 & @@@ repl;

StringReplace[source, repl2]

{"01C10", "02C10T11"}

$\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.