Deleting a sentence that starts with a specific string but ends differently - excel

My VBA is kind of rusty. I have the following problem: I have a column that contains labels for a questionnaire, and there is a lot of extra words tacked on to each label making them almost unreadable. The sentences I need to get rid of are very similar but come with different punctuation and can either appear in the beginning of the cell of in the middle. All sentences start with the word "Using". Here are some examples of cells that I need to clean up (3 main types):
1) "ABC123: - Using a scale of 1 to 5 ... . SomeText1" (sentence to remove starts with "Using" and ends with ".")
2) "DEF456: - Using a 1 to 5 point scale ... : SomeText2" (sentence to remove starts with "Using" and ends with ":")
3) "SomeTextLongerThan20Characters - Using a 1-5 point sca" (sentence to remove starts in the middle of the cell and is cut off in the middle)
I need these 3 cases to look like this:
1) "ABC123: SomeText1"
2) "DEF456: SomeText2"
3) "SomeTextLongerThan20Characters"
Here is my code that I could not get to work:
Sub Edit_String()
'
' Edit_String Macro
' Replaces chosen string with another string or nothing
'
Dim MyRange, c As Range
Dim strA, strB As String
For Each c In MyRange
Select Case Left(c.Text, 20)
Case Left(c.Text, 20) Like "*- Using*"
strA = "- Using*."
Case Left(c.Text, 20) Like "*: Using*"
strA = "- Using*:"
' Case Else
' If Left(c.Text, 20) <> "*Using*" Then strA = "- Using*"
End Select
Selection.Replace What:=strA, Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Next c
MsgBox ("macro finished running")
End Sub
The last Case Else is commented out since I figured I don't need it.
I'd appreciate any help. This seems like a simple wildcard/find/replace issue, but I can't figure it out.

If your original code works for you besides the case statement. This will get the case statement working.
Sub Edit_String()
'
' Edit_String Macro
' Replaces chosen string with another string or nothing
'
Dim MyRange, c As Range
Dim strA, strB As String
[A1] = "ABC123: - Using a scale of 1 to 5. ... . SomeText1"
[A2] = "DEF456: - Using a 1 to 5 point scale ... : SomeText2"
[A3] = "SomeTextLongerThan20Characters - Using a 1-5 point sca"
Set MyRange = [a1:a3]
For Each c In MyRange
c.Select
Select Case True
Case Left(c.Text, 20) Like "*- Using*"
strA = "- Using*."
Case Left(c.Text, 20) Like "*: Using*"
strA = "- Using*:"
' Case Else
' If Left(c.Text, 20) <> "*Using*" Then strA = "- Using*"
End Select
Selection.Replace What:=strA, Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Next c

You should be able to put the following in a blank workbook to test.
Sub GetSentence()
Dim MyRange, c As Range
Dim strA, strB As String
Dim SplitItUp As Variant
Dim LeftPart, RightPart As String
[A1] = "ABC123: - Using a scale of 1 to 5. ... . SomeText1"
[A2] = "DEF456: - Using a 1 to 5 point scale ... : SomeText2"
[A3] = "SomeTextLongerThan20Characters - Using a 1-5 point sca"
Set MyRange = [a1:a3]
UsingLit = " - Using"
For Each c In MyRange
SplitItUp = Split(c.Value, UsingLit)
If UBound(SplitItUp) = 0 Then
Debug.Print UsingLit + " Not Found"
Else
LeftPart = Trim(SplitItUp(0))
RightPart = Trim(SplitItUp(UBound(SplitItUp)))
If InStr(RightPart, ":") Then
SplitItUp = Split(c.Value, ":")
RightPart = SplitItUp(UBound(SplitItUp))
Else
SplitItUp = Split(c.Value, ".")
If UBound(SplitItUp) > 0 Then
RightPart = SplitItUp(UBound(SplitItUp))
Else
RightPart = ""
End If
End If
End If
Debug.Print LeftPart + " " + RightPart
Next c
End Sub

I was googling for this but if there was a way to use excels find and replace to do this. I figured it out myself and I want to put the answer here if anyone else was in the same boat as me. The trick is to type in the search the start of the word with a asterix, add one space, put another asterix and what it should end with.

Related

Replacing Dot to comma in VBA

I have an issue when I try to replace all "." with ","
It works normal when I use Ctrl + H in the Excel Sheet and do it manually.
I have recorded the Macro from what I do in the sheet, and got this code
Columns("Q:S").Select
Selection.Replace What:=".", Replacement:=",", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
But when I run the Macro it only removes the "." , instead of replacing it with "," .
So for instance, if the cell states 4.000 aftter I run the Macro, it returns 4000.
How do I fix this??
I have also tried changing decimal separators in the system, but it does not help me.
Thank you for your help.
This should replace all the periods with commas regardless of data type. (as a string, so you'll no longer be able to easily calculate from them)
You'll still be running into a lot of trouble if you want these numbers to be numbers, with correct separators.
As a side note, When I used find and replace (Ctrl + H) I got the same result where my "4.123" became "4,123.00". This may be related to our system settings.
Sub Test_Replace_Period_with_Comma()
Dim ValueRange As Range
Dim ValueSet
Dim X As Long
Dim Y As Long
Set ValueRange = Intersect(Columns("Q:S"), Sheet8.UsedRange)
ValueSet = ValueRange
If ValueRange.Cells.Count = 1 Then
ReDim ValueSet(1 To 1, 1 To 1)
End If
For X = 1 To UBound(ValueSet, 1)
For Y = 1 To UBound(ValueSet, 2)
'Debug.Print ValueSet(X, Y)
If ValueSet(X, Y) <> "" Then
ValueSet(X, Y) = Replace(CStr(ValueSet(X, Y)), ".", ",", 1, , vbTextCompare)
End If
Next Y
Next X
ValueRange.NumberFormat = "#"
ValueRange = ValueSet
End Sub

Need to reduce runtime to delete strikethrough characters

Excel workbook consist of 10,000 rows and 25 columns and take 15 mins to complete this process. i need to reduce the runtime to complete this process into less than 1 min. kindly help me out from this situtaion.
For Each cl In rng.SpecialCells(2)
For i = Len(cl.Value) To 1 Step -1
If cl.Characters(i, 1).Font.Strikethrough Then
cl.Characters(i, 1).Delete
End If
Next i
Next cl
Very fast approach via xlRangeValueXMLSpreadsheet Value
Using the relatively unknown xlRangeValueXMLSpreadsheet Value, also referred to as ►.Value(11) solves the question by a very simple string replacement (though the xml string handling can reveal to be very complicated under special conditions).
This approach (quickly tested for 10000 rows) seems to be up to 90 times faster as Tim's valid solution refining the original code, but lasting 14 minutes :-)
Sub RemoveStrThr(rng As Range, Optional colOffset As Long = 1)
'a) Get range data as xml spreadsheet value
Dim xmls As String: xmls = rng.Value(xlRangeValueXMLSpreadsheet) ' //alternatively: xmls = rng.Value(11)
'b) find start position of body
Dim pos As Long: pos = InStr(xmls, "<Worksheet ")
'c) define xml spreadsheet parts and remove <S>-node sections in body
Dim head As String: head = Left(xmls, pos - 1)
Dim body As String: body = Mid(xmls, pos)
'remove strike throughs
Dim results: results = Split(Replace(body, "</S>", "^<S>"), "<S>")
results = Filter(results, "^", False) ' negative filtering of special char "^"
body = Join(results, "")
'd) write cleaned range back
rng.Offset(0, colOffset).Value(11) = head & body
End Sub
Example call
Sub TestRemove()
Application.ScreenUpdating = False
Dim t As Double
t = Timer
RemoveStrThr Sheet1.Range("A2:Z10000"), 27 ' << change to your needs
Debug.Print "done", Format(Timer - t, "0.00 secs")
Application.ScreenUpdating = True
End Sub
Help reference links
Excel XlRangeValueDataType enumeration
Excel Range Value
Addendum (due to #Tim' valuable comment)
Note that if the whole cell content should be struck out then this will not remove the struck-out content: there are no <S> or </S> tags in the element, since the strikethrough is applied via a Style rule (via the xml spreadsheet value head).
To meet this eventuality
"...you could add a second step using something like Application.FindFormat.Font.Strikethrough = True: rng.Replace What:="*", Replacement:="", LookAt:=xlPart, SearchOrder:=xlByRows, SearchFormat:=True: Application.FindFormat.Clear to take care of those cells."
Any use of the Characters collection tends to be kind of slow, so the best you can do (beyond turning off screenupdating) is get some minor improvements by (eg) ignoring cells with no strikethrough, checking for cases where all content is struck through, and batching your calls to Delete.
Sub tester()
Dim t
Range("C1:C3").Copy Range("A1:A999") 'creating some dummy cell values (no/mixed/all ST)
Application.ScreenUpdating = False
t = Timer
RemoveStrikeThrough Range("A1:A999")
Debug.Print "done", Timer - t
End Sub
Sub RemoveStrikeThrough(rng As Range)
Dim cl As Range, hasST, i As Long, pos As Long, st As Boolean
For Each cl In rng.Cells
'only process cells which have any strikethrough style applied
' hasST will be False (no ST), True (all ST) or Null (mixed ST)
hasST = cl.Font.Strikethrough
If TypeName(hasST) = "Boolean" Then
If hasST Then
cl.ClearContents 'all text is struck out, so clear the cell
Else
'Debug.Print "No strikethrough", cl.Address
End If
Else
'mixed - do char by char
For i = Len(cl.Value) To 1 Step -1
If cl.Characters(i, 1).Font.Strikethrough Then
If Not st Then 'new run?
st = True
pos = i
End If
Else
If st Then 'previous run?
cl.Characters(i + 1, pos - i).Delete
st = False
End If
End If
Next i
'remove last strikethough if any
If st Then cl.Characters(1, pos).Delete
st = False 'reset this
End If
Next cl
End Sub

Replacing a string of text when only knowing a certain amount of characters

I have a list of PO numbers. They look something like (4010059877-TUR36036133 or TUR6039716## 4010073239). I need to be able to narrow the cell down to only the PO number which is the 4010059877 number. The only consistent part about the part I want to exclude is the "TUR########".
I have worked on code that excludes all non-numeric characters, but some of the cells have these "TUR #'s". I worked on a find and replace with a wildcard "*". I have also searched the web and didn't see anything similar.
Find and Replace attempted code
Sub Replace()
Columns("AJ").Replace What:="TUR*", _
Replacement:="", _
LookAt:=xlPart, _
SearchOrder:=xlByRows, _
MatchCase:=False, _
SearchFormat:=False, _
ReplaceFormat:=False
End Sub
Replacing all non-numeric characters which leaves behind unwanted numbers behind the TUR########
Dim finRow As String
finRow = Sheets("Data").Range("A20000").End(xlUp).Row
Set myRange = Sheets("Data").Range("AK2:AK" & finRow)
For Each myCell In myRange
LastString = ""
For I = 1 To Len(myCell.Value)
mT = Mid(myCell.Value, I, 1)
If mT Like "[0-9]" Then
tString = mT
Else
tString = ""
End If
LastString = LastString & tString
Next I
myCell.Value = LastString
Next
My expected result would be for the TUR######## to be eliminated and replaced with nothing.
You can use InStr() function and then use that to support Left, such that:
loc = instr(mycell,"TUR")
val = left(mycell.value,loc-1)
Edit1:
Due to SJR's comment, will add an example of handling the issue when "TUR" is found in position 1:
loc = instr(mycell,"TUR")
if loc = 1 then
val = ""
else
val = left(mycell.value,loc-1)
end if
Edit2:
Dim val as long 'assumes you will only have a number in the end
val = right(left(mycell.value,12),11)
mycell.value = val
This should cut the first parenthesis off and have no issues with the info after the 11 digit PO. This could even be specific to the case (a switch) where instr(mycell.value,"TUR") is true, in case you have other possible scenarios.
We can also try doing a regex replacement:
Dim Regex As System.Text.RegularExpressions.Regex
Dim input As String = "4010059877-TUR36036133"
Dim output As String = Regex.Replace(input, "([0-9]+)-TUR[0-9]+", "$1")
Console.WriteLine(output)
This outputs: 4010059877

How to modify part of a string with VBA

So for example (the Then statement isn't correct, I'm trying to figure out what to put there):
For i = 1 to 20
If Instr(1, Cells(i, "A"), "#goggle.com") > 0 Then
"#goggle.com" = "#google.com"
Next i
So let's say the email "somebody#goggle.com" is in cell A2, so Instr finds "#goggle.com" in A2. If I want to change the #goggle.com to #google.com, how would I do that?
My goal is to find common misspellings of email domains and fix them.
To fix your code you can use the Replace function, as mentioned
For i = 1 To 20
If InStr(1, Cells(i, "A"), "#goggle.com") > 0 Then
Cells(i, "A") = Replace(Cells(i, "A"), "#goggle.com", "#google.com")
End If
Next
but to be more efficient about all replacements use the Range().Replace method for a list of values and replacements:
Option Explicit
Public Sub fixColumnSpelling()
Const FIND_LIST As String = "#goggle.com #yahho.com #test1.com"
Const REPL_LIST As String = "#google.com #yahoo.com #test2.com"
Dim totalItems As Long, i As Long, findItems As Variant, replItems As Variant
findItems = Split(FIND_LIST)
replItems = Split(REPL_LIST)
totalItems = UBound(findItems)
For i = 0 To totalItems 'bulk replecements in col A
ActiveSheet.UsedRange.Columns(1).Replace _
What:=findItems(i), _
Replacement:=replItems(i), _
LookAt:=xlPart, _
SearchOrder:=xlByColumns, _
MatchCase:=False
Next
End Sub
Look into the Replace Statement.
In this instance:
Replace(Cells(i, "A"), "#google.com", "#gmail.com")
Basically the formula says, in this string `Cells(i,"A") find "#google.com" and replace it with "#gmail.com"
With this you will not need the if statement as the replace function will not replace anything that it does not find. In other words, if "#google.com" is not found in the string it moves on and returns nothing.

VBA - How do i output data to corresponding cell by checking name and emptycell?

Good Day,
really need some help here, im bad at VBA.
Had created a spreadsheet and recorded a macro to record checkin of staff. However, im having difficulties checking out with the corresponding users based on the name.
Could anyone help me out over here?
Thanks. Had attached the spreadsheet for your ref.
http://www.etechnopia.com/vish/Book1ss.xlsm
After much googling, This is what i did based on mikes solution
Dim name As String
Dim id As Integer
Dim checkin As Date
Dim checkout As Date
name = Range("d6").Value
id = Range("d7").Value
checkin = Now
Range("d10") = checkin
Help anyone? im my very best here.
firstly I recommend to use range names for the important cells of your sheet
D6 EmpName
D7 EmpNo
D10 ClockInTime
D11 ClockOutTime
H5..H11 DataTable
This will enable you to reference them by name instead of hardcoding their addresses (bad bad hardcoding :-/ )
Secondly, your [Button] must serve a dual purpose ... it has to decide if a user is clocked in or out and do different things
a hi-level META code, executed at pressing [Button4] could be
if user clocked in
write current time into ClockOutTime ' remark: this may be superfluous
find DataTable record (EmpName, ClockInTime)
write ClockOutTime into record (EmpName, ClockInTime)
erase EmpName, EmpID, ClockInTime, ClockOutTime
else
write current time into ClockInTime
find first blank record in DataTable
write EmpName, EmpID, ClockInTime into DataTable record
endif
How to decide if a user is clocked in? If many users are using the same sheet at the same time (meaning 5 emps go there, write in their names and clock in) you need to examine DataTable for the first record of EmpNane without a ClockOutTime - if found he/she is in and needs to be clocked out.
more later ...
OK ... sorry was interrupted by Lady Gaga concerto in Vienna/AT
so here's a full code for the button
Sub ButtonPressed()
Dim DB As Range, Idx As Integer
Set DB = Range("DataTable")
If Range("EmpName") = "" Or Range("EmpNo") = "" Then
MsgBox "Enter your name and ID before pressing the button", vbCritical + vbOKOnly, "missing input"
Exit Sub
End If
Idx = UserClockedIn()
If Idx <> 0 Then
DB(Idx, 4) = Date + Time()
DB(Idx, 5).Formula = "=" & DB(Idx, 4).Address(RowAbsolute:=False, ColumnAbsolute:=False) & "-" & DB(Idx, 3).Address(RowAbsolute:=False, ColumnAbsolute:=False)
DB(Idx, 5).NumberFormat = "[hh]:mm"
Range("EmpName") = ""
Range("EmpNo") = ""
Else
Idx = 2
Do While DB(Idx, 1) <> ""
Idx = Idx + 1
Loop
DB(Idx, 1) = Range("EmpName")
DB(Idx, 2) = Range("EmpNo")
DB(Idx, 3) = Date + Time()
End If
End Sub
Private Function UserClockedIn() As Integer
Dim DB As Range, Idx As Integer
Set DB = Range("DataTable")
UserClockedIn = 0
Idx = 2
Do While DB(Idx, 1) <> ""
If DB(Idx, 1) = Range("EmpName") And DB(Idx, 2) = Range("EmpNo") And DB(Idx, 4) = "" Then
UserClockedIn = Idx
Exit Function
End If
Idx = Idx + 1
Loop
End Function
#user502908: I have not documented it because I want you to find out exactly what it does and by that have a quick start into Excel-VBA :-) It doesn't do too much and there are some basic thechniques you will apply again & again if you go into VBA ... try to populate ranges "ClockInTime" and "ClockOutTime" :-)))
Book1ssNew.xlsm
have fun
I tried another simpler method which i could cope with
Sub yes()
Dim findId As Integer
Dim FirstAddress As String
Dim FindString As Integer
Dim Rng As Range
FindString = Range("d7").Value
If Trim(FindString) <> "" Then
With Sheets("Sheet1").Range("F1:J100")
Set Rng = .find(What:=FindString, _
After:=.Cells(1), _
LookIn:=xlValues, _
LookAt:=xlWhole, _
SearchOrder:=xlByRows, _
SearchDirection:=xlPrevious, _
MatchCase:=False)
If Not Rng Is Nothing Then
Application.Goto Rng, True
FirstAddress = Rng.Address
Rng.Offset(0, 2).Value = Now()
Else
MsgBox "Nothing found"
End If
End With
End If
End Sub
Search entire spreadsheet given id, when id found, to indicate dynamically the checkin timing.

Resources