'Recursive LAMBDA to replace characters by specific substitutes from a lookup table
The goal is to iterate through rows of the character table and replace each character with it's substitute.
The character table in this example is ={"&","&";"<","<";">",">";"'","'";"""","""}
, or:
*(Sidenote: "&","&"
must be last on the list in this exact case, or it will replace other occurrences from previous substitutions, since we're going last to first.)
Formula:
=LAMBDA(XML,Pos,
LET(
Cls,{"&","&";"<","<";">",">";"'","'";"""","""},
Row,IF(ISOMITTED(Pos),ROWS(Cls),Pos),
Crf,INDEX(Cls,Row,1),
Crr,INDEX(Cls,Row,2),
Sub,SUBSTITUTE(XML,Crf,Crr),
IF(Row=0,XML,ENCODEXML(Sub,Row-1))
))
Expected result for =ENCODEXML("sl < dk & jf")
would be sl < dk & jf
I'm getting #VALUE!
error instead.
Solution 1:[1]
- You need to have an exit on the recursive:
=LAMBDA(XML,Pos,
LET(
Cls,{"&","&";"<","<";">",">";"'","'";"""","""},
Row,IF(ISOMITTED(Pos),ROWS(Cls),Pos),
Crf,INDEX(Cls,Row,1),
Crr,INDEX(Cls,Row,2),
Sub,SUBSTITUTE(XML,Crf,Crr),
IF(Row>1,ENCODEXML(Sub,Row-1),Sub)
))
- You need to add the
,
in the call:
=ENCODEXML("sl < dk & jf",)
Or as @Filcuk discovered(and I learned just now) if it is optional it needs to be declared using []
ie:
=LAMBDA(XML,[Pos],
LET(
Cls,{"&","&";"<","<";">",">";"'","'";"""","""},
Row,IF(ISOMITTED(Pos),ROWS(Cls),Pos),
Crf,INDEX(Cls,Row,1),
Crr,INDEX(Cls,Row,2),
Sub,SUBSTITUTE(XML,Crf,Crr),
IF(Row>1,ENCODEXML(Sub,Row-1),Sub)
))
Then the ,
is not needed:
=ENCODEXML("sl < dk & jf")
Solution 2:[2]
Just to complement the answer above by Scott; using a recursive lambda through the name manager seems to be obsolete (if one doesn't explicitly need a named function for later use). Since REDUCE()
is a recursive function on it's own. Therefor, one can apply the following structure:
=LET(X,<LookupTable>,REDUCE(<InputValue>,INDEX(X,0,1),LAMBDA(a,b,SUBSTITUTE(a,b,VLOOKUP(b,X,<ReturnCol>,0)))))
Where:
<LookupTable>
- Refers to a matrix where the leftmost column holds the lookup values. This is particularly true forVLOOKUP()
however, with different structures one can start usingXLOOKUP()
(to make the solution more applicable);<InputValue>
- A reference to the input string you need to apply the substitution to;<ReturnCol>
- In addition to the 1st point: when one usesVLOOKUP()
an index refering to the column with the replacement values need to be given;
In the case given by OP this would translate to:
=LET(X,{"&","&";"<","<";">",">";"'","'";"""","""},REDUCE("sl < dk & jf",INDEX(X,0,1),LAMBDA(a,b,SUBSTITUTE(a,b,VLOOKUP(b,X,2,0)))))
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |