Here are the sample text:
Input:
1. AbST/1234342
2. Y_sRR/666
3. B.RE/1234
Output:
1. AST
2. YRR
3. BRE
Basically I need a formula to get the first three capital letters before the slash and disregard lowercase and symbols.
I don't know how this could be done without VBA, but with VBA it is straightforward enough:
Function ExtractUppers(s As String, k As Long) As String
'Extracts the first k upper case letters from
's, returning the result as a string
'if there are fewer than k, the function returns
'those that are found
Dim letters As Variant
Dim i As Long, j As Long
Dim c As String
ReDim letters(0 To k - 1) As String
For i = 1 To Len(s)
c = Mid(s, i, 1)
If "A" <= c And c <= "Z" Then
letters(j) = c
j = j + 1
If j = k Then Exit For
End If
Next i
ExtractUppers = Join(letters, "")
End Function
Then, for example, =ExtractUppers("B.RE/1234",3) would evaluate to "BRE".
Here is another formula option if you have access to CONCAT function. Check the link for more information.
Formula in B1:
=CONCAT(IF(CODE(MID(A1,ROW($A$1:INDEX(A:A,LEN(A1))),1))=TRANSPOSE(ROW($A$65:$A$90)),MID(A1,ROW($A$1:INDEX(A:A,LEN(A1))),1),""))
NOTE: It's an array formula that you need to enter through Ctrl+Shift+Enter
I have not taken into consideration the "/" as though it seems there are not going to be capitals after it in your sample data. If there are, you have to replace the above formula with:
=CONCAT(IF(CODE(MID(LEFT(A1,SEARCH("/",A1)),ROW($A$1:INDEX(A:A,SEARCH("/",A1))),1))=TRANSPOSE(ROW($A$65:$A$90)),MID(LEFT(A1,SEARCH("/",A1)),ROW($A$1:INDEX(A:A,SEARCH("/",A1))),1),""))
If you have Office 365 / Excel 2016+ with the TEXTJOIN function, you can use the array formula:
=IFERROR(LEFT(TEXTJOIN("",TRUE,IF((CODE(MID(A1,ROW(INDIRECT("1:"&FIND("/",A1)-1)),1))>=65)*(CODE(MID(A1,ROW(INDIRECT("1:"&FIND("/",A1)-1)),1))<=90),MID(A1,ROW(INDIRECT("1:"&FIND("/",A1)-1)),1),"")),3),"")
As pointed out by #JvdV, you can replace the TEXTJOIN function with the CONCAT function which is simpler when a delimiter is not required:
=IFERROR(LEFT(CONCAT(IF((CODE(MID(A1,ROW(INDIRECT("1:"&FIND("/",A1)-1)),1))>=65)*(CODE(MID(A1,ROW(INDIRECT("1:"&FIND("/",A1)-1)),1))<=90),MID(A1,ROW(INDIRECT("1:"&FIND("/",A1)-1)),1),"")),3),"")
To enter/confirm an array formula, hold down ctrl + shift while hitting enter. If you do this correctly, Excel will place braces {...} around the formula seen in the formula bar.
If you do not have the TEXTJOIN function, you can use a User Defined Function written in VBA.
Here is an example using Regular Expressions:
Option Explicit
Function upper3(S As String) As String
Dim RE As Object, MC As Object
Dim I As Long, sTemp As String
Set RE = CreateObject("vbscript.regexp")
With RE
.Global = True
.ignorecase = False
.Pattern = "[A-Z](?=.*/)"
Set MC = .Execute(S)
If MC.Count >= 3 Then
For I = 0 To 2
sTemp = sTemp & MC(I)
Next I
upper3 = sTemp
End If
End With
End Function
Either gives the following results:
However, the formula will return 1-3 uppercase letters preceding the /; the UDF only returns a result if there are at least 3 uppercase letters preceding the /. Either can be changed to the other depending on your requirements.
Related
As mentioned in the title, I wonder if there is any way to use built-in functions in excel to see whether a cell contains a specific number and count the total numbers in the cell. The cell can contain a list of numbers seperated by comas, for instance, "1,4,7" or ranges "10-25" or a combination of both. See the print screen.
No, there is not, but you could write a VBA function to do that, something like:
Function NumberInValues(number As String, values As String) As Boolean
Dim n As Integer
n = CInt(number)
Dim parts() As String
parts = Split(values, ",")
For i = LBound(parts) To UBound(parts)
parts(i) = Replace(parts(i), " ", "")
Next
Dim p() As String
Dim first As Integer
Dim last As Integer
Dim tmp As Integer
For i = LBound(parts) To UBound(parts)
p = Split(parts(i), "-")
' If there is only one entry, check for equality:
If UBound(p) - LBound(p) = 0 Then
If n = CInt(p(LBound(p))) Then
NumberInValues = True
Exit Function
End If
Else
' Check against the range of values: assumes the entry is first-last, does not
' check for last > first.
first = CInt(p(LBound(p)))
last = CInt(p(UBound(p)))
If n >= first And n <= last Then
NumberInValues = True
Exit Function
End If
End If
Next
NumberInValues = False
End Function
and then your cell C2 would be
=NumberInValues(B2,A2)
Calculating how many numbers there are in the ranges would be more complicated as numbers and ranges could overlap.
The key part of implementing this is to create a List or Array of individual numbers that includes all the Numbers represented in the first column.
Once that is done, it is trivial to check for an included, or do a count.
This VBA routine returns a list of the numbers
Option Explicit
Function createNumberList(s)
Dim AL As Object
Dim v, w, x, y, I As Long
Set AL = CreateObject("System.Collections.ArrayList")
v = Split(s, ",")
For Each w In v
'If you need to avoid duplicate entries in the array
'uncomment the If Not lines below and remove the terminal double-quote
If IsNumeric(w) Then
'If Not AL.contains(w) Then _"
AL.Add CLng(w)
Else
x = Split(w, "-")
For I = x(0) To x(1)
'If Not AL.contains(I) Then _"
AL.Add I
Next I
End If
Next w
createNumberList = AL.toarray
End Function
IF your numeric ranges might be overlapping, you will need to create a Unique array. You can do that by changing the AL.Add function to first check if the number is contained in the list. In the code above, you can see instructions for that modification.
You can then use this UDF in your table:
C2: =OR($B2=createNumberList($A2))
D2: =COUNT(createNumberList($A2))
Here is a possible formula solution using filterxml as suggested in the comment:
=LET(split,FILTERXML("<s><t>+"&SUBSTITUTE(A2,",","</t><t>+")&"</t></s>","//s/t"),
leftn,LEFT(split,FIND("-",split&"-")-1),
rightn,IFERROR(RIGHT(split,LEN(split)-FIND("-",split)),leftn),
SUM(rightn-leftn+1))
The columns from F onwards show the steps for the string in A2. I had to put plus signs in because Excel converted a substring like "10-15" etc. into a date as usual.
Then to find if a number (in C2 say) is present:
=LET(split,FILTERXML("<s><t>+"&SUBSTITUTE(A2,",","</t><t>+")&"</t></s>","//s/t"),
leftn,LEFT(split,FIND("-",split&"-")-1),
rightn,IFERROR(RIGHT(split,LEN(split)-FIND("-",split)),leftn),
SUM((--leftn<=C2)*(--rightn>=C2))>0)
As noted by #Ron Rosenfeld, it's possible that there may be duplication within the list: the Count formula would be susceptible to double counting in this case, but the Check (to see if a number was in the list) would give the correct result. So the assumptions are:
(1) No duplication (I think it would be fairly straightforward to check for duplication, but less easy to correct it)
(2) No range in wrong order like 15-10 (although this could easily be fixed by putting ABS around the subtraction in the first formula).
Here is a little cheeky piece of code for a VBA solution:
Function pageCount(s As String)
s = Replace(s, ",", ",A")
s = Replace(s, "-", ":A")
s = "A" & s
' s now looks like a list of ranges e.g. "1,2-3" would give "A1,A2:A3"
pageCount = Union(Range(s), Range(s)).Count
End Function
because after all the ranges in the question behave exactly like Excel ranges don't they?
and for inclusion (of a single page)
Function includes(s As String, m As String) As Boolean
Dim isect As Range
s = Replace(s, ",", ",A")
s = Replace(s, "-", ":A")
s = "A" & s
Set isect = Application.Intersect(Range(s), Range("A" & m))
includes = Not (isect Is Nothing)
End Function
If I search for the term 'tfo' in the cell value 'TFO_xyz' then the result should be TRUE.
If I search for the term 'tfo' in the cell value 'TFO systems' then the result should be TRUE.
If I search for the term 'tfo' in the cell value 'spring TFO' then the result should be TRUE.
BUT if I check 'tfo' in the cell value 'Platform' then I want the result as FALSE
I have used the formula =IF(COUNTIF(A2,"*tfo*"),"TRUE","FALSE"), but this wont give result as FALSE when I check 'tfo' in the word 'Platform'
NOTE:
Platform should be false because tfo is coming in between a word. I'm looking result as True for cell values with just the word tfo like in tfo<space>America or TFO_America or <space>TFO systems. But I want FALSE result for the words Platform and portfolio because in these two words the term tfo comes in between alphabets.
Try this:
Dim x As Long: x = 1
With Sheet1
Do While x <= .Cells(.Rows.Count, 1).End(xlUp).Row
If VBA.Left(.Cells(x, 1).Value, 3) = "tfo" Or VBA.Right(.Cells(x, 1).Value, 3) = "tfo" Then
.Cells(x, 2).Value = True
End If
x = x + 1
Loop
End With
Try this formula. This assumes that word tfo will be at the beginning or end
Just make sure to place appropriate cell names where i have 'A2' in the formula
=IF(OR(PROPER(LEFT(A2,3))="tfo",PROPER(RIGHT(A2,3))="tfo"),TRUE,FALSE)
Test Cases Below:
My suggestion is to spend sometime to know your data and create a white-list.
Since there is no easy way to properly do fuzzy search in strings.
Function TFO_Search(strText As String) As Boolean
Dim ArryString As Variant
Dim ArryWhitelist As Variant
' Create a White-List Array
ArryWhitelist = Array("TFO_", "TFO ", "_TFO", " TFO", "tfoAmerica")
For Each ArryString In ArryWhitelist
If InStr(UCase(strText), UCase(ArryString)) > 0 Then 'force to UPPER CASE
TFO_Search = True
Exit Function
Else
TFO_Search = False
End If
Next
End Function
I see two dimensions of complexity in your question:
Where does the key word occur in the text (beginning, middle, end)
What are the characters that separate words.
The first one is fixed size, you need to handle three cases. The second one depends on the number of characters you want to accept as delimiters. Below I assumed that you accept space and underscore, however, you may expand this set by inserting more SUBSTITUTE function calls.
In my table, $A2 is the cell in which you search for the keyword, while B$1 contains the keyword.
To standardize the separator character, you need the formula:
B2=SUBSTITUTE($A2,"_"," ")
To check if the string starts with the keyword:
C2=--(LEFT($B2,LEN(B$1)+1)=B$1&" ")
To check if the string ends with the keyword:
D2=--(RIGHT($B2,LEN(B$1)+1)=" "&B$1)
To check if the keyword is in the middle of the string:
E2=--(LEN(SUBSTITUTE(UPPER($B2)," "&UPPER(B$1)&" ",""))<LEN($B2))
To evaluate the above three cases:
F2=--(0<$C2+$D2+$E2)
If you want to use a single cell, combine the formulas into:
G2=--(0<--(LEFT(SUBSTITUTE($A2,"_"," "),LEN(B$1)+1)=B$1&" ")+--(RIGHT(SUBSTITUTE($A2,"_"," "),LEN(B$1)+1)=" "&B$1)+--(LEN(SUBSTITUTE(UPPER(SUBSTITUTE($A2,"_"," "))," "&UPPER(B$1)&" ",""))<LEN(SUBSTITUTE($A2,"_"," "))))
It is not very readable in the end but I don't think there was an easier solution using Formulas only.
Note: If you want to modify the set of characters accepted as delimiters, add more SUBSTITUTE function calls to B2, then copy the Formula of F2 into notepad and replace $C2 with the formula of C2, etc., then replace $B2 with the updated Formula of B2.
Update
Building on the idea in Ron Rosenfelds comment to tigeravatar's answer, the formula can be simplified (the beginning, middle, ending cases can be joined):
=--(LEN(SUBSTITUTE(" "&UPPER($B2)&" "," "&UPPER(B$1)&" ",""))<LEN($B2))
After substituting $B2 with its formula:
=--(LEN(SUBSTITUTE(" "&UPPER(SUBSTITUTE($A2,"_"," "))&" "," "&UPPER(B$1)&" ",""))<LEN(SUBSTITUTE($A2,"_"," ")))
This formula will return true if TFO is at the beginning or end of any given word, or by itself, in the text string. It also checks every word in the text string, so TFO can be at beginning, middle, or end. The formula assumes that if a word starts or ends with TFO, then the result should be TRUE (as is the case for tfoAmerica so same rule would apply to tform), else FALSE.
=OR(ISNUMBER(SEARCH({" tfo","tfo "}," "&SUBSTITUTE(A2,"_"," ")&" ")))
Here are its results:
EDIT:
In the event that the result should only be TRUE if TFO is found by itself, then this version of the formula will suffice:
=ISNUMBER(SEARCH(" tfo "," "&SUBSTITUTE(A2,"_"," ")&" "))
Image showing results of second version:
If you can rely on VBA, then regex is a more flexible solution.
There is a good summary, of how to use them in VBA: How to use Regular Expressions (Regex) in Microsoft Excel both in-cell and loops
For your keyword search problem I wrote the following:
Option Explicit
' Include: Tools > References > Microsoft VBScript Regular Expressions 5.5 (C:\Windows\SysWOW64\vbscript.dll\3)
Public Function SearchKeyWord(strHay As String, strNail As String, Optional strDelimiters As String = " _,.;/", Optional lngNthOccurrence As Long = 1) As Long ' Returns 1-based index of nth occurrence or 0 if not found
Dim strPattern As String: strPattern = CreatePattern(strNail, strDelimiters)
Dim rgxKeyWord As RegExp: Set rgxKeyWord = CreateRegex(strPattern, True)
Dim mtcResult As MatchCollection: Set mtcResult = rgxKeyWord.Execute(strHay)
If (0 <= lngNthOccurrence - 1) And (lngNthOccurrence - 1 < mtcResult.Count) Then
Dim mthResult As Match: Set mthResult = mtcResult(lngNthOccurrence - 1)
SearchKeyWord = mthResult.FirstIndex + Len(mthResult.SubMatches(0)) + 1
Else
SearchKeyWord = 0
End If
End Function
Private Function CreateRegex(strPattern As String, Optional blnIgnoreCase As Boolean = False, Optional blnMultiLine As Boolean = True, Optional blnGlobal As Boolean = True) As RegExp
Dim rgxResult As RegExp: Set rgxResult = New RegExp
With rgxResult
.Pattern = strPattern
.IgnoreCase = blnIgnoreCase
.MultiLine = blnMultiLine
.Global = blnGlobal
End With
Set CreateRegex = rgxResult
End Function
Private Function CreatePattern(strNail As String, strDelimiters As String) As String
Dim strDelimitersEscaped As String: strDelimitersEscaped = RegexEscape(strDelimiters)
Dim strPattern As String: strPattern = "(^|[" & strDelimitersEscaped & "]+)(" & RegexEscape(strNail) & ")($|[" & strDelimitersEscaped & "]+)"
CreatePattern = strPattern
End Function
Private Function RegexEscape(strOriginal As String) As String
Dim strEscaped As String: strEscaped = vbNullString
Dim i As Long: For i = 1 To Len(strOriginal)
Dim strChar As String: strChar = Mid(strOriginal, i, 1)
Select Case strChar
Case ".", "$", "^", "{", "[", "(", "|", ")", "*", "+", "?", "\"
strEscaped = strEscaped & "\" & strChar
Case Else
strEscaped = strEscaped & strChar
End Select
Next i
RegexEscape = strEscaped
End Function
Once you have the above in a Module, you can insert formulas like the following:
=SearchKeyWord($A1,"tfo")
where A1 contains e.g. "tfo America".
As a third parameter, you may specify, which characters you want to treat as delimiters, by default they are space, underscore, comma, dot, semicolon and slash.
The return value is the position of the nth occurrence of the keyword, where n is the value of the fourth parameter (default: 1), or 0 if not found.
To check if the keyword is present in A1, compare the result to 0, which means not found:
=--(SearchKeyWord($A1,"tfo")<>0)
I have a cell that contains usernames assigned to projects like this
,FC757_random_name,AP372_another_one,FC782_again_different,FC082_samesamebutdifferent,
I need to only extract the alphanumeric values the expressions start with, so everything in between , and _.
I made it work for one expression with the following, but I need all of them.
= MID(A1;FIND(",";A1)+1;FIND("_";A1)-FIND(",";A1)-1)
I also tinkered with Text to Data, but couldn't make it work for multiple lines at once.
Ideally this would work only with formulas, but I guess (/fear) I'll need VBA or Macros, which I have never worked with before.
All help will be appreciated!
Here is a regex based User Defined Function.
Option Explicit
Function extractMultipleExpressions(str As String, _
Optional delim As String = ", ")
Dim n As Long, nums() As Variant
Static rgx As Object, cmat As Object
'with rgx as static, it only has to be created once; beneficial when filling a long column with this UDF
If rgx Is Nothing Then
Set rgx = CreateObject("VBScript.RegExp")
End If
extractMultipleExpressions = vbNullString
With rgx
.Global = True
.MultiLine = False
.Pattern = "[A-Z]{2}[0-9]{3}"
If .Test(str) Then
Set cmat = .Execute(str)
'resize the nums array to accept the matches
ReDim nums(cmat.Count - 1)
'populate the nums array with the matches
For n = LBound(nums) To UBound(nums)
nums(n) = cmat.Item(n)
Next n
'convert the nums array to a delimited string
extractMultipleExpressions = Join(nums, delim)
End If
End With
End Function
I believe you are looking for something like this Press Alt + F11 and then choose Insert > Module and then paste the following code:
Public Function GetUsers(UserNameProject As String)
Dim userArray() As String
Dim users As String
Dim intPos As Integer
'this will split the users into an array based on the commas
userArray = Split(UserNameProject, ",")
'loop through the array and process any non blank element and extract user
'based on the position of the first underscore
For i = LBound(userArray) To UBound(userArray)
If Len(Trim(userArray(i))) > 0 Then
intPos = InStr(1, userArray(i), "_")
users = users & "," & Left(userArray(i), intPos - 1)
End If
Next
GetUsers = users
End Function
If your string is in A1 then use by putting =GetUsers(A1) in the approiate cell. I think this should get you started!
To clean the data of extra commas, use this formula in cell B1:
=TRIM(SUBSTITUTE(SUBSTITUTE(TRIM(SUBSTITUTE(SUBSTITUTE(A1;" ";"||");";";" "));" ";";");"||";" "))
Then use this formula in cell C1 and copy over and down to extract just the part you want from each section:
=IFERROR(INDEX(TRIM(LEFT(SUBSTITUTE(TRIM(MID(SUBSTITUTE($B1;";";REPT(" ";LEN($B1)));LEN($B1)*(ROW($A$1:INDEX($A:$A;LEN($B1)-LEN(SUBSTITUTE($B1;";";""))+1))-1)+1;LEN($B1)));"_";REPT(" ";LEN($B1)));LEN($B1)));COLUMN(A1));"")
I am trying to extract all numbers from a string with a function in Excel.
In the second time, I would like to extract the maximum value contains in the string.
My string look likes:
ATCG=12.5,TTA=2.5,TGC=60.28
Desired output: 60.28
In a first time, I am trying to extract all numbers with my function but it stops only on the first figure.
Function MyCode(ByVal txt As String) As String
With CreateObject("VBScript.RegExp")
.Pattern = "\d.+"
If .test(txt) Then MyCode = .Execute(txt)(0)
End With
End Function
Here is some VBA (not vbscript) that you can adapt to you needs:
Public Function MyCode(ByVal txt As String) As String
Dim maxi As Double, db As Double
maxi = -9999
arr = Split(Replace(txt, "=", ","), ",")
For Each a In arr
If IsNumeric(a) Then
db = CDbl(a)
If db > maxi Then maxi = db
End If
Next a
MyCode = CStr(maxi)
End Function
NOTE:
This gives a String and not a Number.
EDIT#1:
In Excel-VBA, the code must be placed in a standard module.
User Defined Functions (UDFs) are very easy to install and use:
ALT-F11 brings up the VBE window
ALT-I
ALT-M opens a fresh module
paste the stuff in and close the VBE window
If you save the workbook, the UDF will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the UDF:
bring up the VBE window as above
clear the code out
close the VBE window
To use the UDF from Excel:
=MyCode(A1)
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
and for specifics on UDFs, see:
http://www.cpearson.com/excel/WritingFunctionsInVBA.aspx
Macros must be enabled for this to work!
You don't really need VBA for this if you have a version of Excel (2010+) that includes the AGGREGATE function, you can do it with a worksheet formula:
=AGGREGATE(14,6,--TRIM(MID(SUBSTITUTE(SUBSTITUTE(A1,",",REPT(" ",99)),"=",REPT(" ",99)),seq_99,99)),1)
where seq_99 is a Named Formula that refers to:
=IF(ROW(INDEX($1:$65535,1,1):INDEX($1:$65535,255,1))=1,1,(ROW(INDEX($1:$65535,1,1):INDEX($1:$65535,255,1))-1)*99)
The function results in an array, some of the values are numeric; the AGGREGATE function returns the largest value in the array, ignoring errors.
The formulas below are for earlier versions of Excel and must be entered as array formulas, by holding down ctrl + shift while hitting enter If you do this correctly, Excel will place braces {...} around the formula.
If you have 2007, you can use IFERROR
=MAX(IFERROR(--TRIM(MID(SUBSTITUTE(SUBSTITUTE(A2,",",REPT(" ",99)),"=",REPT(" ",99)),seq_99,99)),0))
For earlier versions, you can use:
=MAX(IF(ISERROR(--TRIM(MID(SUBSTITUTE(SUBSTITUTE(A3,",",REPT(" ",99)),"=",REPT(" ",99)),seq_99,99))),0,--TRIM(MID(SUBSTITUTE(SUBSTITUTE(A3,",",REPT(" ",99)),"=",REPT(" ",99)),seq_99,99))))
Your decimal separator may be different from the US decimal separator.
Public Function MyCode(ByVal txt As String) As String
Dim maxi As Double, db As Double
maxi = -9 ^ 9
arr = Split(txt, ",")
For Each a In arr
If InStr(a, "=") Then
a = Mid(a, InStr(a, "=") + 1)
ar = Replace(a, ".", Format(0, "."))
If IsNumeric(ar) Then
db = ar
If db > maxi Then maxi = db: ok = True
End If
End If
Next a
If ok = True Then
MyCode = CStr(maxi)
End If
End Function
Collect all of the mixed numbers as doubles in an array and return the maximum value.
Option Explicit
Option Base 0 '<~~this is the default but I've included it because it has to be 0
Function maxNums(str As String)
Dim n As Long, nums() As Variant
Static rgx As Object, cmat As Object
'with rgx as static, it only has to be created once; beneficial when filling a long column with this UDF
If rgx Is Nothing Then
Set rgx = CreateObject("VBScript.RegExp")
End If
maxNums = vbNullString
With rgx
.Global = True
.MultiLine = False
.Pattern = "\d*\.\d*"
If .Test(str) Then
Set cmat = .Execute(str)
'resize the nums array to accept the matches
ReDim nums(cmat.Count - 1)
'populate the nums array with the matches
For n = LBound(nums) To UBound(nums)
nums(n) = CDbl(cmat.Item(n))
Next n
'test array
'Debug.Print Join(nums, ", ")
'return the maximum value found
maxNums = Application.Max(nums)
End If
End With
End Function
I'm trying to prepare a spreadsheet for a report in excel vba. Unforturnately there are some wierd characters here that need to be replaced. Easy enough, except for this chracter:
¦
I can't seem to be able to paste that character into the editor into a string replace function. When I try, the output is _. I then thought to refer to it by it's Chr code. A quick look up said it was Chr(166). http://www.gtwiki.org/mwiki/?title=VB_Chr_Values
Replace(s, "â€" + Chr(166), "...")
But this is not that character at all (at least on Mac excel). I tried:
For i = 1 To 255
Debug.Print Chr(i)
Next i
And I didn't see this character anywhere. Does anyone know how I can reference this character in vba code in order to replace it?
Not sure if regexp is available for vba-mac, but you could simplify your existing code greatly as below.
Uses a sample Strin
Dim strIn As String
strIn = "1â€1â€x123"
Do While InStr(strIn, "â€") > 0
Mid$(strIn, InStr(strIn, "â€"), 3) = "..."
Loop
Click on a cell containing your miscreant character and run this small macro:
Sub WhatIsIt()
Dim s As String, mesage As String
Dim L As Long
s = ActiveCell.Text
L = Len(s)
For i = 1 To L
ch = Mid(s, i, 1)
cd = Asc(ch)
mesage = mesage & ch & " " & cd & vbCrLf
Next i
MsgBox mesage
End Sub
It should reveal the characters in the cell and their codes.
It's dirty, but here's the workaround that I used to solve this problem. I knew that my issue character was always after "â€", so the idea was to replace the character that came after those 2. I don't really know how to replace a character at a position in a string, so my idea was to covert the string to an array of characters and replace the array at those specific indexes. Here's what it looks like:
Do While InStr(s, "â€") > 1
num2 = InStr(s, "â€")
arr = stringToArray(s)
arr(num2 - 1) = "<~>"
arr(num2) = "<~>"
arr(num2 + 1) = "<~>"
s = Replace(arrayToString(arr), "<~><~><~>", "...")
Loop
...
Function stringToArray(ByVal my_string As String) As Variant
Dim buff() As String
ReDim buff(Len(my_string) - 1)
For i = 1 To Len(my_string)
buff(i - 1) = Mid$(my_string, i, 1)
Next
stringToArray = buff
End Function
Function arrayToString(ByVal arr As Variant) As String
Dim s As String
For Each j In arr
s = s & j
Next j
arrayToString = s
End Function
In practice, what I replaced those indexes with is something that had to be unique but recognizable. Then i can replace my unique characters with whatever I want. There are sure to be edge cases, but for now it gets the job done. stringToArray function pulled from: Split string into array of characters?