# How to modify a string of symbols based on the positions of $1$'s in a list of Booleans?

Given a list of Booleans:

exampleInput = {1, 1, 0, 1, 0, 0, 1, 0};


and given the string:

string = "\\xa , \\xb , \\xc , \\xd , \\xe , \\xf , \\xg , \\xh";


The challenge is to replace the lower case letters $$\{a,b,c,d,e,f,g,h\}$$ with capital letters $$\{A,B,C,D,E,F,G,H\}$$ at the positions where $$1$$'s occur in the list of Booleans.

exampleOutput = "\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"


## Challenge/Question:

come up with an elegant or surprising way to do this.

all code for convenience:

exampleInput = {1, 1, 0, 1, 0, 0, 1, 0};
string = "\\xa , \\xb , \\xc , \\xd , \\xe , \\xf , \\xg , \\xh";


Make list of functions out of exampleInput:

foo = exampleInput /. {0 -> Identity, 1 -> ToUpperCase};


You can use foo with StringReplace or with StringReplacePart in several ways:

StringReplace[string, "x" ~~ a_ :> "x"<> Last[foo = RotateLeft[foo]][a]]


or (using @J.M.'s regular expression pattern):

StringReplace[string,
RegularExpression["(?![x])[a-z]"] :> Last[foo = RotateLeft[foo]]["\$0"]]


or

Block[{i = 1}, StringReplace[string, "x" ~~ a_ :> "x"<> foo[[i++]][a]]]


or

pos = 1 + StringPosition[string, "x"];

StringReplacePart[string, Construct @@@ Thread[{foo, StringTake[string, pos]}], pos]


or

StringReplacePart[string, MapThread[Compose, {foo, StringTake[string, pos]}], pos]


StringRiffle[MapAt[StringReplace["x" ~~ a_ :> "x" <> ToUpperCase[a]],
StringSplit[string, ","], Position[exampleInput, 1]], ","]


"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

Alternatively,

spos = 1 + Pick[StringPosition[string, "x"], exampleInput, 1];

StringReplacePart[string, ToUpperCase[StringTake[string, spos]], spos]


"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

and

ClearAll[stringMapAt]
stringMapAt = StringJoin@MapAt[#, Characters@#2, #3] &;

stringMapAt[ToUpperCase, string, spos[[All, {1}]]]


"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

A variation of the first answer in kglr's post that doesn't deconstruct and reconstruct the list:

Module[{i = 1},
StringReplace[
string, "x" ~~ a_ :> "x" <> If[exampleInput[[i++]] == 1, ToUpperCase@a, a]
]
]


"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

Slightly more verbose but not requiring checking with the If statement:

Module[{i = 1},
StringReplace[string,
"x" ~~ z_ :>  "x" <> FromCharacterCode[First@ToCharacterCode[z] - 32 exampleInput[[i++]]]
]
]


Here's how to use a regex with "negative lookahead" in conjunction with Pick[]:

With[{pos = Pick[StringPosition[string, RegularExpression["((?![x])[a-z])"]],
exampleInput, 1]},
StringReplacePart[string, ToUpperCase[StringTake[string, pos]], pos]]
"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"

exampleInput = {1, 1, 0, 1, 0, 0, 1, 0};
string = "\\xa , \\xb , \\xc , \\xd , \\xe , \\xf , \\xg , \\xh";


Since this question seems more along the lines of code golf (which I'm all in favor of), I won't put generality as much of a priority.

## Replacement

With[
{lets = Pick[Alphabet[][[;; Length@exampleInput]], exampleInput, 1](*{a,b,...,h}*)},
StringReplace[string, char : Alternatives @@ lets :> ToUpperCase@char]
]

"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"


## Brute force

With[
{lets = Pick[Alphabet[][[;; Length@exampleInput]], exampleInput, 1]},
If[MemberQ[lets, #], ToUpperCase@#, #] & /@ Characters@string // StringJoin
]

"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"


## Pattern Exploitation

And if we want to use the symmetry/pattern that each a, b, etc are separated by 6 characters (starting at the third character of the string).

StringJoin@MapAt[
ToUpperCase,
Characters@string,
]

"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"


## Pattern exploitation, indicator functions, and generalized inner products

First we notice that the indexing letters (a, ..., h), denoted by let, all have 5 characters between them.

Then we pad the indicator function exampleInput (in the sense of which letters, out of all the letters, are to be capitalized) to be the same length as the string

indic = (exampleInput /. x : (0 | 1) :> {0, 0, 0, 0, 0, x} // Flatten)[[4 ;;]]


stripping off unnecessary leading zeros. This gives a list of ones where the letters-to-be-capitalized are, and zeros elsewhere.

Then, being inspired from @kglr's foo

funcs = indic /. {0 -> Identity, 1 -> ToUpperCase}


Then we take the generalized inner product between funcs and the character list

Inner[#1@#2 & (*or Construct in version >= 11.3*), funcs, Characters@string, StringJoin]

"\\xA , \\xB , \\xc , \\xD , \\xe , \\xf , \\xG , \\xh"


Or all together

With[
{indic = (exampleInput /. x : (0 | 1) :> {0, 0, 0, 0, 0, x} // Flatten)[[4 ;;]]},
Inner[#1@#2 &, indic /. {0 -> Identity, 1 -> ToUpperCase}, Characters@string, StringJoin]
]