Related
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.
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")
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 for VLOOKUP() however, with different structures one can start using XLOOKUP() (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 uses VLOOKUP() 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)))))
Is there a way to put a Char in this case a "0" into a string?
I'd like to put a zero at position 8
For example:
device 4 -> device 04
I hope i could explain the problem well.
newString = Left(existingString, 7) & "0" & Mid(existingString, 8) is one way.
& is the string concatenation operator in VBA, the two argument Mid runs from a given position to the end of a string.
This can also be done using a worksheet function:
=REPLACE(D1,8,0,"0")
And the Replace method is also a member of the WorksheetFunction in VBA, so you could write it as a VBA function also. Note that this is different from the VBA Replace function.
I am trying to set up a function to reformat a string that will later be concatenated. An example string would look like this:
Standard_H2_W1_Launch_123x456_S_40K_AB
Though sometimes the "S" doesn't exist, and sometimes the "40K" is "60K" or not there, and the "_AB" can also be "_CD" or _"EF". Finally, all underscores need to be changed to hyphens. The final product should look like this:
Standard-H2-W1-Launch-123x456-
I have four functions that if ran one after the other will take care of all of this:
=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A2,"_AB","_"),"_CD","_"),"_EF","_")
=SUBSTITUTE(SUBSTITUTE(B2,"_40K",""),"_60K","")
=SUBSTITUTE(C2,"_S_","_")
=SUBSTITUTE(D2,"_","-")
I've tried a number of ways of combining these into one function, but I'm relatively new to this level of excel so I'm at a loss. Is there anyway to combine all of this so that it executes one command after the other in one cell?
To simply combine them you can place them all together like this:
=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A2,"_AB","_"),"_CD","_"),"_EF","_"),"_40K",""),"_60K",""),"_S_","_"),"_","-")
(note that this may pass the older Excel limit of 7 nested statements. I'm testing in Excel 2010
Another way to do it is by utilizing Left and Right functions.
This assumes that the changing data on the end is always present and is 8 characters long
=SUBSTITUTE(LEFT(A2,LEN(A2)-8),"_","-")
This will achieve the same resulting string
If the string doesn't always end with 8 characters that you want to strip off you can search for the "_S" and get the current location. Try this:
=SUBSTITUTE(LEFT(A2,FIND("_S",A2,1)),"_","-")
nesting SUBSTITUTE() in a string can be nasty, however, it's always possible to arrange it:
Thanks for the idea of breaking down a formula Werner!
Using Alt+Enter allows one to put each bit of a complex substitute formula on separate lines: they become easier to follow and automatically line themselves up when Enter is pressed.
Just make sure you have enough end statements to match the number of substitute( lines either side of the cell reference.
As in this example:
=
substitute(
substitute(
substitute(
substitute(
B11
,"(","")
,")","")
,"[","")
,"]","")
becomes:
=
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(
SUBSTITUTE(B12,"(",""),")",""),"[",""),"]","")
which works fine as is, but one can always delete the extra paragraphs manually:
=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(B12,"(",""),")",""),"[",""),"]","")
Name > substitute()
[American Samoa] > American Samoa
I would use the following approach:
=SUBSTITUTE(LEFT(A2,LEN(A2)-X),"_","-")
where X denotes the length of things you're not after. And, for X I'd use
(ISERROR(FIND("_S",A2,1))*2)+
(ISERROR(FIND("_40K",A2,1))*4)+
(ISERROR(FIND("_60K",A2,1))*4)+
(ISERROR(FIND("_AB",A2,1))*3)+
(ISERROR(FIND("_CD",A2,1))*3)+
(ISERROR(FIND("_EF",A2,1))*3)
The above ISERROR(FIND("X",.,.))*x will return 0 if X is not found and x (the length of X) if it is found. So technically you're trimming A2 from the right with possible matches.
The advantage of this approach above the other mentioned is that it's more apparent what substitution (or removal) is taking place, since the "substitution" is not nested.
=SUBSTITUTE(text, old_text, new_text)
if: a=!, b=#, c=#,... x=>, y=?, z=~, " "=" "
then: abcdefghijklmnopqrstuvwxyz ... try this out
equals: !##$%^&*()-=+[]\{}|;:/<>?~ ... ;}? ;*(| ]:;
RULES:
(1) text to substitute is in cell A1
(2) max 64 substitution levels (the formula below only has 27 levels [alphabet + space])
(2) "old_text" cannot also be a "new_text" (ie: if a=z .: z cannot be "old text")
---so if a=z,b=y,...y=b,z=a, then the result is
---abcdefghijklmnopqrstuvwxyz = zyxwvutsrqponnopqrstuvwxyz (and z changes to a then changes back to z) ... (pattern starts to fail after m=n, n=m... and n becomes n)
The formula is:
=SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(A1,"a","!"),"b","#"),"c","#"),"d","$"),"e","%"),"f","^"),"g","&"),"h","*"),"i","("),"j",")"),"k","-"),"l","="),"m","+"),"n","["),"o","]"),"p","\"),"q","{"),"r","}"),"s","|"),"t",";"),"u",":"),"v","/"),"w","<"),"x",">"),"y","?"),"z","~")," "," ")
Is it possible to remove the " character using an Excel formula?
I tried the REPLACE function like this
REPLACE(<sometext>, """, "")
and this
REPLACE((<sometext>, char(34), "")
but it doesn't work.
NB: I am using the Polish version of Excel, so it is probable, that the syntax is different than in the English version. For example, in Polish formulas we use ; instead of , as argument separator.
The quotation mark character " must be represented by two of them "" when it's inside a string, to revolve the ambiguity between this "textual" quotation mark and the "code" quotation marks that delimit the beginning and end of your string.
In short, the right formula to remove all " from the text in A1 is:
=SUBSTITUTE(A1,"""","")
with emphasis on the fact that the old_text argument has to be """" (four quotes) and not """ (three quotes) as you wrote in your question.
And maybe SUBSTITUTE is called Replace in the Polish edition? Anyhow, you have to use the Polish equivalent of SUBSTITUTE and whatever argument separator is appropriate (; or ,).
Replace doesn't work the way, you want it to.
Use SUBSTITUTE.
=SUBSTITUTE(A1, CHAR(34), "-")
OR use ; as separator for your example
=SUBSTITUTE(A1; CHAR(34); "-")
I've done some Googling, and can't find anything, though maybe I'm just looking in the wrong places. I'm also not very adept at VBA, but I'm sure I can figure it out with the right pointers :)
I have a string I'm building that's a concatenation of various cells, based on various conditions. I hit these in order.
=IF(A405<>A404,G405,G405&H404)
What I want to do is go back through my concatenated list, removing a superseded value if the superseder is in the list.
For example, see the following list:
A, D, G, Y, Z
I want to remove D if and only if Y is present.
How would I go about this? (VBA or in-cell, though I'd prefer in-cell)
Try:
=IF(ISERROR(FIND("Y",A1)),A1,SUBSTITUTE(A1,"D, ",""))
But that assumes you always have the comma and space following the D.
Firstly, why not keep a string array instead as you go through all the cells, then concatenate it all at the end?
Otherwise, you'll be using string functions like INSTR and MID to do something like:
start1 = instr(myLongString,"Y, ")
if start1 > 0 Then
start2 = instr(myLongString,"D, ")
if start2 > 0 then
newLongString = left(myLongString, start2 - 1) & _
mid(myLongString, start2 + 3)
end if
end if
But, as I said, I would keep an array that is easy to loop through, then once you have all the values you KNOW you will use, just concatenate them at the end.
VBA : You can always use the regexp object.
I think that gives you the ability to test anything on your script as long as you build correctly the regular expression.
Check out : http://msdn.microsoft.com/en-us/library/yab2dx62(VS.85).aspx ( for regexp reference )
and a simple tool to test your regexps : http://www.codehouse.com/webmaster_tools/regex/
In-cell: you could do it in a more excel friendly way:
suppose on column A:A you have the values.
You can add a new column where you perform the check
if(indirect("A"&row()) <> indirect("A"&row()-1), indirect("G"&row()), indirect("G"&row())& indirect("H"&row()))
or whatever the values are. I guess however that on one branch of the if statement the value should be blank. After that you concatenate only the B:B column values ( skipping blanks if needed ).
Hope this helps.
It's probably easier to start at the end, make your additions to the beginning of the string, and only add D if Y is not present.
I guess D could appear anywhere, so how about:
If InStr(strString, "Y") > 0 Then
strString = Replace(strString, "d", "")
strString = Replace(strString, " ", "")
strString = Replace(strString, " ,", "")
strString = Replace(strString, ",,", ",")
End If
If there are not too many of these combinations that you want to remove, you can use =IF(FIND("D"; A2)> 0; REPLACE(A2;1;3;"");A2).
I just got this as a possible solution via email, too:
=IF(A15<>A14,G15,IF(OR(AND(G15="CR247, ",ISNUMBER(FIND("CR247, ",H14))),AND(G15="CR149, ",ISNUMBER(FIND("CR215, ",H14))),AND(G15="CR149, ",ISNUMBER(FIND("CR180, ",H14))),AND(G15="CR180, ",ISNUMBER(FIND("CR215, ",H14))),G15="CR113, "),H14,G15&H14))
(this has the "real" values with precedence rules)
It looks relatively similar to #Joseph's answer.
Is there a better solution?