2 Corrected typo
source | link

Looks like a bug to me. We can see what going on by looking this evaluation:

StringReplace[
  "a\n_b_\nc",
  s : Shortest[StartOfLine ~~ ___ ~~ "b" ~~ ___ ~~ EndOfLine] -> "*" ~~ s ~~ "*"]

"*a _b_* c"

Clearly, the 1st "\n" is not being handled properly. However and strangely,

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ s___ ~~ EndOfLine] :-> "*" <>~~ s <>~~ "*"]

works and gives

"*a* *_b_* *c*"

From this 2nd result, we can derive a work-around.

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ s___ ~~ EndOfLine] :> If[StringContainsQ[s, "b"], "XXX", s]]

"a XXX c"

Not very pretty, I admit.

Another sign pointing to Shortest being buggy. Evaluating

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ _ ~~ "b" ~~ ___ ~~ EndOfLine] -> "XXX"]

gives the correct result.

Looks like a bug to me. We can see what going on by looking this evaluation:

StringReplace[
  "a\n_b_\nc",
  s : Shortest[StartOfLine ~~ ___ ~~ "b" ~~ ___ ~~ EndOfLine] -> "*" ~~ s ~~ "*"]

"*a _b_* c"

Clearly, the 1st "\n" is not being handled properly. However and strangely,

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ s___ ~~ EndOfLine] :> "*" <> s <> "*"]

works and gives

"*a* *_b_* *c*"

From this 2nd result, we can derive a work-around.

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ s___ ~~ EndOfLine] :> If[StringContainsQ[s, "b"], "XXX", s]]

"a XXX c"

Not very pretty, I admit.

Another sign pointing to Shortest being buggy. Evaluating

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ _ ~~ "b" ~~ ___ ~~ EndOfLine] -> "XXX"]

gives the correct result.

Looks like a bug to me. We can see what going on by looking this evaluation:

StringReplace[
  "a\n_b_\nc",
  s : Shortest[StartOfLine ~~ ___ ~~ "b" ~~ ___ ~~ EndOfLine] -> "*" ~~ s ~~ "*"]

"*a _b_* c"

Clearly, the 1st "\n" is not being handled properly. However and strangely,

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ s___ ~~ EndOfLine] -> "*" ~~ s ~~ "*"]

works and gives

"*a* *_b_* *c*"

From this 2nd result, we can derive a work-around.

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ s___ ~~ EndOfLine] :> If[StringContainsQ[s, "b"], "XXX", s]]

"a XXX c"

Not very pretty, I admit.

Another sign pointing to Shortest being buggy. Evaluating

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ _ ~~ "b" ~~ ___ ~~ EndOfLine] -> "XXX"]

gives the correct result.

1
source | link

Looks like a bug to me. We can see what going on by looking this evaluation:

StringReplace[
  "a\n_b_\nc",
  s : Shortest[StartOfLine ~~ ___ ~~ "b" ~~ ___ ~~ EndOfLine] -> "*" ~~ s ~~ "*"]

"*a _b_* c"

Clearly, the 1st "\n" is not being handled properly. However and strangely,

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ s___ ~~ EndOfLine] :> "*" <> s <> "*"]

works and gives

"*a* *_b_* *c*"

From this 2nd result, we can derive a work-around.

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ s___ ~~ EndOfLine] :> If[StringContainsQ[s, "b"], "XXX", s]]

"a XXX c"

Not very pretty, I admit.

Another sign pointing to Shortest being buggy. Evaluating

StringReplace[
  "a\n_b_\nc",
  Shortest[StartOfLine ~~ _ ~~ "b" ~~ ___ ~~ EndOfLine] -> "XXX"]

gives the correct result.