# Highlighting text with StringReplacePart but also using Style, Subscript

For a Natural Language Processing analysis task it's desirable to highlight a text string programmatically according to XML tags that reference specific words or phrases.

The XML tags specify the character ranges in the input string as well as give other information such as identifiers and other codes.

Since character ranges are provided in the XML markup, originally I thought StringReplacePart would do the job, but it doesn't seem possible to transform the string into more general expressions, eg using Subscript or Style.

For example (please excuse I'm showing only a fragment due to Protected Health Information), given the (partial) input text:

In[566]:= StringTake[I2B2[1, text], -500]

Out[566]= " pain and was treated with Percocet . She went for a \
debridement of her left calf lesion on 10/2/93 and was started \
empirically on IV ceftriaxone which was changed to po doxycycline on \
the day of discharge . A follow-up CT scan was done which did not \
show any evidence for splenomegaly or hepatomegaly . The 1 cm cyst \
which was seen in 10/92 was still present . There was a question of a \
cyst in her kidney with a stone right below the cyst , although this \
did not seem to be clinically significant ."


And the XML tag:

In[581]:= Cases[I2B2[1, tags],
XMLElement[
"EVENT", {id_, start_, end_, text_ -> "a stone", modality_,
polarity_, type_}, _]]

Out[581]= {XMLElement[
"EVENT", {"id" -> "E75", "start" -> "2476", "end" -> "2483",
"text" -> "a stone", "modality" -> "POSSIBLE", "polarity" -> "POS",
"type" -> "PROBLEM"}, {}]}


The following StringReplacePart works (to ALL CAPS) since the output is still a string:

In[577]:=  StringReplacePart[
StringTake[I2B2[1, text], -500],
"A STONE", {2476,
2483 - 1} - ((I2B2[1, text] // StringLength ) - 500)]

Out[577]= " pain and was treated with Percocet . She went for a \
debridement of her left calf lesion on 10/2/93 and was started \
empirically on IV ceftriaxone which was changed to po doxycycline on \
the day of discharge . A follow-up CT scan was done which did not \
show any evidence for splenomegaly or hepatomegaly . The 1 cm cyst \
which was seen in 10/92 was still present . There was a question of a \
cyst in her kidney with A STONE right below the cyst , although this \
did not seem to be clinically significant ."


But the following does not since I'm trying to highlight in Red using Style:

In[578]:=  StringReplacePart[
StringTake[I2B2[1, text], -500],
Style["a stone",
Red], {2476, 2483 - 1} - ((I2B2[1, text] // StringLength ) - 500)]

Out[578]= StringReplacePart[" pain and was treated with Percocet . \
She went for a debridement of her left calf lesion on 10/2/93 and was \
started empirically on IV ceftriaxone which was changed to po \
doxycycline on the day of discharge . A follow-up CT scan was done \
which did not show any evidence for splenomegaly or hepatomegaly . \
The 1 cm cyst which was seen in 10/92 was still present . There was a \
question of a cyst in her kidney with a stone right below the cyst , \
although this did not seem to be clinically significant .", \!$$\* StyleBox["\<\"a stone\"\>", StripOnInput->False, LineColor->RGBColor[1, 0, 0], FrontFaceColor->RGBColor[1, 0, 0], BackFaceColor->RGBColor[1, 0, 0], GraphicsColor->RGBColor[1, 0, 0], FontColor->RGBColor[1, 0, 0]]$$, {413, 419}]


Are there functions similar to StringReplacePart that can output more general expressions? Or in any case how to perform the desired highlighting with Subscript and Style?

-
This is a potentially very deep question. While styling a single section of a string (which becomes a Row) is trivial, styling multiple sections, potentially overlapping, becomes far from trivial. –  Mr.Wizard Jun 30 '12 at 22:25

As far as I know you can't put style information in strings themselves. They're just a bunch of characters from a character table. You can style the output of a string, but not put that in a string itself. So, StringReplacePart doesn't make sense here.

You could solve it as follows:

Row[{"There was a question of a cyst in her kidney with",
Style[" a stone", Red],
" right below the cyst , although this did not seem to be clinically significant ."}]


or you could think of working in low-level StyleBox-es.

You could use StringSplit to split the string around "a stone", or use StringPosition and StringTake.

-
Thanks Sjoerd. StringSplit can't be used here because repeated substrings can have unique identifiers. StringTake followed by extracting the complementary ranges and sort them before applying Row works: complementaryRanges = Cases[ ReplacePart[(# - {0, 1}) & /@ Partition[ Drop[Flatten[ SortBy[Join[events[[All, 1]], timex[[All, 1]]], #[[1]] &]], 1], 2, 2, 1], {-1, 2} -> StringLength[I2B2[1, text]]], {s_, e_} /; e > s];Row[Last /@ SortBy[Join[events, timex, {#, StringTake[I2B2[file, text], #]} & /@ complementaryRanges], #[[1]] &]] –  alancalvitti Jul 1 '12 at 20:00

I needed some similar task that it was basically about, take a whatever text ( a string) and replace or highlighting some word or list of words with color, to notice them. I did this:

texto = "Este seńor JUANCHO, al ver a este seńor al cual yo estaba \
asdfasdf, viendo que asdfadsfasdf, entonces me llama por \
teléfono a la casa y me dice"

palabra = "en";

Row[Riffle[StringSplit[texto, palabra ],
Style[palabra, Red, FontWeight -> Bold]]]


-
Very nice and compact, thank you. What if you had multiple distinct substrings to highlight in different colors? –  alancalvitti Aug 26 '13 at 15:53
Actually, I should do that with a list, so I use a iterative For over List, and with !StringFreeQ of regular expression from word in List, highlight it. –  d555 Aug 27 '13 at 18:06

I think you can use StyleBox in a String like this:

"\*StyleBox[\"a stone\", FontColor->RGBColor[1, 0, 0]]"


which will give a result the same as Style["a stone", Red].

Note you should specify color by RGBColor[...] but not Red, I think the reason is the same as this post.

Edit:

A more complicated example with SubscriptBox:

StringReplacePart["1234567890",
"\*StyleBox[\!$$XXXX\_2$$,FontColor->RGBColor[1,0,0]]",
{5, 7}]


Boxes have special form in String, you can use ToString[exp,form] to get them:

ToString[
Style[
HoldForm[
Sum[(Derivative[k][f][0]/k!)*x^k, {k, 0, Infinity}]
],
FontFamily -> "Times"],