Find "carriage return" in a mail.body - vba

I have mails like this :
Hello,
Please note we did ... at 16h15
Actions done: Rebuilding etc
sincerely
Mr.
The actions change in every mail and what I want is to insert the action in my Excel. The problem is that I don't know how to get the "carriage return" (idk if this is the right name, this is what traduction gave me).
What I find in internet is that vbLfChr(10) is the "carriage return".
What I tried is to find the beginning :
TechnicPosition= InStr(1, .Body, "Actions done: ")
TechnicAction= Mid(.Body, TechnicPosition, 14) ' first char from the action
But I can't get the last char (first "carriage return" from TechnicAction).
I tried many things like : InStr(TechnicPosition, .Body, vbCrLf)
My question : how to get a sentence that begin from a word to a "carriage return" (the first that comes after the beginning word) ?

The carriage return in the email body is usually vbNewline
This is how I usually do it
Sub Sample()
Dim sBody As String
Dim MyAr
Dim i As Long
'
'~~> Rest of your code
'
sBody = oMail.Body
'~~> For testing purpose
'sBody = "Hello," & vbNewLine & vbNewLine
'sBody = sBody & "Please note we did ... at 16h15" & vbNewLine & vbNewLine
'sBody = sBody & "Actions done: Rebuilding etc" & vbNewLine & vbNewLine
'sBody = sBody & "Sincerely"
'~~> Split the email body on vbnewline and store it in array
MyAr = Split(sBody, vbNewLine)
'~~> Loop through array
For i = LBound(MyAr) To UBound(MyAr)
'~~> Check if the line has "Actions done:"
If InStr(1, MyAr(i), "Actions done:") Then
'~~> This would give you "Rebuilding etc"
'~~> Split the line on "Actions done:"
'~~> You will get an array. Ar(0) will have "Actions done:"
'~~> And Ar(1) will have what you are looking for so we use
'~~> Split()(1) directly to access that item
MsgBox Split(MyAr(i), "Actions done:")(1)
Exit For
End If
Next i
End Sub
Edit
ANOTHER WAY

Try this:
TechnicPosition = InStr(1, .Body, "Actions done: ")
TechnicEndPosition = InStr(TechnicPosition, .Body, Chr(10))
TechnicAction = Mid(.Body, TechnicPosition + 14, TechnicEndPosition - TechnicPosition - 14)

Loop through the body to see what the character is:
For i = 1 To Len(.Body)
If Not Mid(.Body, i, 1) Like "[A-Za-z0-9,'?!"".:]" Then
Debug.Print Asc(Mid(.Body, i, 1))
End If
Next
Once you've found the Asc() value, split the body on it and return the second index:
TechnicAction = Split(.Body, Asc(10))(1) '// Or whatever Asc() is required

Related

VBA - Comparing Layouts of Two Files

I am trying to figure out how to check that the layout (not the full content) of a CSV file is the same of that in the preceding month (or, if that file doesn't exist, the last available CSV file).
Often companies change the format/layout of their CSV extracts, so I want my code to automatically detect any changes (new columns added, changing order of columns, etc).
Please let me know if you have an idea of how this could be achieved!
Thanks in advance!
Please, try the next code. It assumes that the csv to be compared is comma separated and ending lines are vbCrLf:
Private Sub CheckCSVfile()
Dim ws As Worksheet, strFile As String, ans As VbMsgBoxResult, sep As String
Dim arrRef, arrCSV, cols, i As Long, strProbl As String
ans = MsgBox("Is the active sheet the one you wan to use as reference to compare the CSV file structure?" & vbCrLf & _
"If this is the situation, please press ""Yes""!", vbYesNo, "Confirm the active sheet as reference")
If ans <> vbYes Then Exit Sub
Set ws = ActiveSheet
'Put the first sheet row values in an array (2D array):
arrRef = ws.Range(ws.cells(1, 1), ws.cells(1, ws.cells(1, ws.Columns.count).End(xlToLeft).Column)).value
''Browse for the .csv file to be checked:
strFile = Application.GetOpenFilename("Text Files (*.csv),*.csv", , "Please select the csv file to be checked.")
If strFile = "False" Then Exit Sub
'Put the content of the csv file in an array (split by the line ending separator). If not vbCrLf, use the appropriate one:
arrCSV = Split(CreateObject("Scripting.FileSystemObject").OpenTextFile(strFile, 1).ReadAll, vbCrLf)
sep = "," 'the csv file separator. Use here the correct one if not comma
cols = Split(arrCSV(0), sep) 'number of columns of the first csv file row (zero based array)
If UBound(cols) + 1 <> UBound(arrRef, 2) Then '+ 1 for the first array because it is of 0 based type
strProbl = strProbl & "The number of columns in the new csv file is different (" & UBound(cols) & " against " & UBound(arrRef) & ")." & vbCrLf
End If
'Comparing each header:
For i = 0 To UBound(arrRef, 2) - 1
If UCase(arrRef(1, i + 1)) <> UCase(cols(i)) Then
strProbl = strProbl & "The value in the column " & i + 1 & " is different (" & cols(i) & " against " & arrRef(1, i + 1) & ")" & vbCrLf
End If
Next i
Stop
If strProbl <> "" Then
MsgBox "The new csv file has a different structure: " & vbCrLf & vbCrLf & strProbl, vbCritical, "Structure problems..."
Else
MsgBox "The both files structure is the same!", vbInformation, "No any structure problem"
End If
End Sub
You must firstly open and activate the sheet of the previous csv file (to be used as reference) and then run the above code.
Please, send some feedback after testing it...

How to make an SRT file into a dataset?

Is it possible to turn an SRT file, which is used for subtitles in videos into a dataset?
When imported into Excel, the SRT file format looks like this:
1
00:00:03,000 --> 00:00:04,000
OVERLAPS PURE COINCIDENCE THAT
...
This pattern continues as time in the "video"/transcript goes on. I'd like to format the SRT file this way:
number ; start ; end ; text
1 ; 00:00:03,000 ; 00:00:04,000 ; OVERLAPS PURE COINCIDENCE THAT
The VBA procedure below loads a standard .srt (SubRip Movie Subtitle File) from a local file and splits it into rows/columns on the active Excel worksheet.
Import SRT subtitles from Local File:
Sub importSRTfromFile(fName As String)
'Loads SRT from local file and converts to columns in Active Worksheet
Dim sIn As String, sOut As String, sArr() As String, x As Long
'load file
Open fName For Input As #1
While Not EOF(1)
Line Input #1, sIn
sOut = sOut & sIn & vbLf
Wend
Close #1
'convert LFs to delimiters & split into array
sOut = Replace(sOut, vbLf & vbLf, vbCr)
sOut = Replace(Replace(sOut, vbLf, "|"), " --> ", "|")
sArr = Split(sOut, vbCr)
'check if activesheet is blank
If ActiveSheet.UsedRange.Cells.Count > 1 Then
If MsgBox(UBound(sArr) & " rows found." & vbLf & vbLf & _
"Okay to clear worksheet '" & ActiveSheet.Name & "'?", _
vbOKCancel, "Delete Existing Data?") <> vbOK Then Exit Sub
ActiveSheet.Cells.ClearContents
End If
'breakout into rows
For x = 1 To UBound(sArr)
Range("A" & x) = sArr(x)
Next x
'split into columns
Columns("A:A").TextToColumns Destination:=Range("A1"), _
DataType:=xlDelimited, Other:=True, OtherChar:="|"
MsgBox "Imported " & UBound(sArr) & " rows from:" & vbLf & fName
End Sub
Example Usage:
Sub test_FileImport()
importSRTfromFile "c:\yourPath\yourFilename.srt"
End Sub
Import SRT subtitles from Website URL:
Alternatively, you can import an .srt (or other similar text files) from a Website URL such as https://subtitle-index.org/ with this:
Sub importSRTfromWeb(url As String)
'Loads SRT from URL and converts to columns in Active Worksheet
Dim sIn As String, sOut As String, sArr() As String, rw As Long
Dim httpData() As Byte, XMLHTTP As Object
'load file from URL
Set XMLHTTP = CreateObject("MSXML2.XMLHTTP")
XMLHTTP.Open "GET", url, False
XMLHTTP.send
httpData = XMLHTTP.responseBody
Set XMLHTTP = Nothing
sOut = StrConv(httpData, vbUnicode)
'convert LFs to delimiters & split into array
sOut = Replace(sOut, vbLf & vbLf, vbCr)
sOut = Replace(Replace(sOut, vbLf, "|"), " --> ", "|")
sArr = Split(sOut, vbCr)
'check if activesheet is blank
If ActiveSheet.UsedRange.Cells.Count > 1 Then
If MsgBox(UBound(sArr) & " rows found." & vbLf & vbLf & _
"Okay to clear worksheet '" & ActiveSheet.Name & "'?", _
vbOKCancel, "Delete Existing Data?") <> vbOK Then Exit Sub
ActiveSheet.Cells.ClearContents
End If
'breakout into rows
For rw = 1 To UBound(sArr)
Range("A" & rw) = sArr(rw)
Next rw
'split into columns
Columns("A:A").TextToColumns Destination:=Range("A1"), _
DataType:=xlDelimited, Other:=True, OtherChar:="|"
MsgBox "Imported " & UBound(sArr) & " rows from:" & vbLf & url
End Sub
Example Usage:
Sub testImport()
importSRTfromWeb _
"https://subtitle-index.org/download/4670541854528212663953859964/SRT/Pulp+Fiction"
End Sub
Many sites host free .srt's; you may have to right-click the download button to copy the link (which may have an .srt extension or might be a pointer, like the example above). The procedure won't work on .zip'd files.
More Information:
Wikipedia : SubRip & SRT
MSDN : Split Function (VBA)
Wikipedia : Newline characters
MSDN : UBound Function
MSDN : Range.TextToColumns Method (Excel)
SubRip Official Website
in the above code :
'breakout into rows
For rw = 1 To UBound(sArr)
Range("A" & rw) = sArr(rw)
Next rw
should be replaced with:
'breakout into rows
For rw = 0 To UBound(sArr)
Range("A" & rw+1) = sArr(rw)
Next rw
else the output will start from line 2
I used Vim and wrote a quick regex to convert a .srt into a .csv file for a translator friend who needed a similar conversion. The csv file can then be opened in Excel / LibreOffice and saved as .xls, .ods or whatever.
My friend didn't need the subtitle numbers to appear in the first column so the regex code looks like this :
set fileencoding=utf-8
%s/"/""/g
g/^\d\+$/d
%s#^\(.*\) --> \(.*\)\n#"\1","\2","#g
%s/\n^$/"/g
Variant to keep the sub numbering :
set fileencoding=utf-8
%s/"/""/g
%s#\(^\d\+\)$\n^\(.*\) --> \(.*\)\n#"\1","\2","\3","#g
%s/\n^$/"/g
Save this code into a text file with the .vim extension, then source this file when editing your .srt in Vim / Gvim. Save the result as a .csv. Enjoy the magic of Regexes !
NB : my code uses commas as field separators. Change the commas into semi-colons in the above code to use semi-colons. I've also added double-quotes as string delimitors in case double-quotes and commas occur in the subtitle text. Much more error proof !

How to improve this VBA code to add Carbon Copy into it

I am trying to improve my code my from previous post Predetermine the cells with the data to send emails to put some Carbon Copy (CC) on the line code. What I am trying to figure out is that there are some companies that might be my CC's, that depends of the type of email I want to send.
Example: I created 2 lists of CC emails That I might wanna send emails.
In front of the company's name I Concatenate all the emails from the list to only one cell.
How can I put this into the code that I can choose the name of the company and all the emails from that company goes to the CC list?
Thank you one more time for all the helping you guys are giving me.
I am going to copy the code from the previous post just to be easier to read:
Sub SendEMail()
'update by Extendoffice 20160506
Dim xEmail As String
Dim xSubj As String
Dim xMsg As String
Dim xURL As String
Dim i As Integer
Dim k As Double
Dim xCell As Range
Dim xRg As Range
Dim xTxt As String
On Error Resume Next
xTxt = ActiveWindow.RangeSelection.Address
Set xRg = Range("A2:C6")
If xRg Is Nothing Then Exit Sub
For i = 1 To xRg.Rows.Count
' Get the email address
xEmail = xRg.Cells(i, 2)
' Message subject
xSubj = "Your Registration Code"
' Compose the message
xMsg = ""
xMsg = xMsg & "Dear " & xRg.Cells(i, 1) & "," & vbCrLf & vbCrLf
xMsg = xMsg & " This is your Registration Code "
xMsg = xMsg & xRg.Cells(i, 3).Text & "." & vbCrLf & vbCrLf
xMsg = xMsg & " please try it, and glad to get your feedback! " & vbCrLf
xMsg = xMsg & "Skyyang"
' Replace spaces with %20 (hex)
xSubj = Application.WorksheetFunction.Substitute(xSubj, " ", "%20")
xMsg = Application.WorksheetFunction.Substitute(xMsg, " ", "%20")
' Replace carriage returns with %0D%0A (hex)
xMsg = Application.WorksheetFunction.Substitute(xMsg, vbCrLf, "%0D%0A")
' Create the URL
xURL = "mailto:" & xEmail & "?subject=" & xSubj & "&body=" & xMsg
' Execute the URL (start the email client)
ShellExecute 0&, vbNullString, xURL, vbNullString, vbNullString, vbNormalFocus
' Wait two seconds before sending keystrokes
Application.DisplayKeys "%s"
Next
End Sub
1-In your code after:
If xRg Is Nothing Then Exit Sub
insert:
Dim CCCompany As Integer
Dim ccstr As String
ccstr = FindMyCompany()
If ccstr = vbNullString Then
CCCompany = MsgBox("No cc email selected. Are you sure you want to proceed?", vbYesNo + vbQuestion, "To be or not to be")
If CCCompany = vbYes Then
xCC = ""
Else
Exit Sub
End If
Else
xCC = "&cc=" & ccstr
End If
2-Then replace:
xURL = "mailto:" & xEmail & "?subject=" & xSubj & "&body=" & xMsg
with:
xURL = "mailto:" & xEmail & "?subject=" & xSubj & xCC & "&body=" & xMsg
3-Finally add below function after your sub:
Function FindMyCompany() As String
Dim rng As Range
Dim i As Long
Dim xCC As String
Application.DisplayAlerts = False
Set rng = Application.InputBox("Select desired Company column or any cell in that column", _
"Get Company Column", Type:=8)
Application.DisplayAlerts = True
i = 1
Do Until IsEmpty(Cells(i, rng.Column))
Set crng = Cells(i, rng.Column)
If InStr(crng.Value, "#") Then
xCC = xCC & crng.Value & ";"
End If
i = i + 1
Loop
FindMyCompany = Left(xCC, Len(xCC) - 1)
End Function
4-Allocate your Companies along with email addresses to different columns as shown below. You can set as many company as you need this way.
5-When you run your code, simply select your desired company cell and click ok.
Important note: You can select the whole column, a range of cells from desired column or a single cell in the desired column. Your code will still work since it extracts only column number from your selection.
Edit: If you want to repeat this process for selecting bcc emails, right after selecting ccs, you can use the same function with different assignment like this:
Dim CCCompany As Integer
Dim ccstr As String
Dim bccstr As String
ccstr = FindMyCompany()
bccstr = FindMyCompany()
If ccstr = vbNullString Then
CCCompany = MsgBox("No cc email selected. Are you sure you want to proceed?", vbYesNo + vbQuestion, "To be or not to be")
If CCCompany = vbYes Then
xCC = ""
Else
Exit Sub
End If
Else
xCC = "&cc=" & ccstr
End If
If bccstr = vbNullString Then
BCCCompany = MsgBox("No cc email selected. Are you sure you want to proceed?", vbYesNo + vbQuestion, "To be or not to be")
If BCCCompany = vbYes Then
xBCC = ""
Else
Exit Sub
End If
Else
xBCC = "&bcc=" & bccstr
End If
and amend your xURL like this
xURL = "mailto:" & xEmail & "?subject=" & xSubj & xCC & xBCC & "&body=" & xMsg
The short answer (albeit somewhat janky) might be to:
Make Column D you "cc" column which will point to the concatenated value of the cc's (C10)
make an xCC = xRg.Cells(i, 4)
make xURL = "mailto:" & xEmail & "?subject=" & xSubj & "&body=" & xMsg & "&cc=" & xCC
I do want to point out that this is prone to becoming a mess, but it should solve your immediate need.
I would recommend the solution below for a better approach:
Create 2 new columns (let's say J and K). J will hold the Name of the companies, (like XCCompany) and K will hold a single email address corresponding to the company. In your example you would do this three times for each company (since they both have three cc's and end up with six records) -- the company name will be the same for three but the email addresses will be different. We want the company names to be the same so that we can search on them.
ADDITIONALLY, in column D you can store the name of the company to CC (XCCompany) and when you press the button the macro will lookup email addresses that correspond to the company name (using the info in J and K), concatenate them, and put them as cc's. I found a nifty little UDF function that does this http://www.excelfox.com/forum/showthread.php/345-LookUp-Value-and-Concatenate-All-Found-Results.
If you wanted to take this approach, declare the function in a module (maybe under your SendEmail function) and instead of setting xCC as indicated above, set it as indicated below (make sure to keep the changes to xURL):
xCC = LookUpConcat(xRg.Cells(i, 4), Range("J2:J100"), Range("K2:K100"), ";")
(Note I only went up to K100 and J100 for performance issues, your list could grow longer and if so, you would want to adjust accordingly.)
Good Luck!

Excel vba open all word document in a folder and print by getting number of copies from user

I am new to Macro
By googling I coded this and I have changed some part for my use.
Problem is Runtime error is coming. And I don't know how to print all word documents in folder both .doc and .docx
My Requirement
Want to print all word document in folder A (both .doc and .docx).
Print active document ( Number of copies want to be get from User ).
Close active document.
Repeat 2 and 3 for all document in folder A
My code will get page number to print from case selected by the user
case 1 will print 1st two pages one by one.
case 2 will print 3rd to reset of the pages.
case 3 will print full document.
In my office duplex is default printer setup to print. But I will be using letter head. I need this macro to solve my issue. I tried simplex macro code to print but its not working.
Sub prnt()
Dim c As Integer
Dim i As Integer
Dim strName As String
'get print type
strName = InputBox(Prompt:="Choose Your Option" & vbNewLine & "" & vbNewLine & "1. Letter Head" & vbNewLine & "2. A4 Sheet" & vbNewLine & "3. Comp Plan" & vbNewLine & "", _
Title:="ENTER YOUR PRINT TYPE", Default:="Your Choice here")
If strName = "Your Choice here" Or strName = vbNullString Then
MsgBox "Sorry...! Choose Correct option"
Exit Sub
Else
'case to choose option
Select Case strName
Case "1"
Dim file
Dim path As String
Dim ans As String
'get number of copies from user
c = InputBox("Please enter number of copies")
ans = MsgBox("Are you sure you want to print " & _
c & "?", _
vbQuestion + vbYesNo, "Print pages")
If ans = vbNo Then
Exit Sub
Else
'path to the folder
path = "E:\print\"
file = Dir(path & "*.docx")
Do While file ""
Documents.Open Filename:=path & file
For i = 1 To 2 'loop 2 pages
ActiveDocument.PrintOut , Copies:=c, Range:=wdPrintRangeOfPages, Pages:=i
Next
ActiveDocument.Close
' set file to next in Dir
file = Dir()
Loop
End If
Case "2"
Case "3"
Case Else
MsgBox "Sorry...! Choose Correct option"
End Select
End If
End Sub
There's bad programming practice to work on strings instead of numbers.
See this:
Sub Test()
Dim noofcopies As Integer
noofcopies = GetNumberOfCopies()
MsgBox noofcopies
End Sub
Function GetNumberOfCopies() As Integer
Dim iRetVal As Integer
On Error GoTo Err_GetNumberOfCopies
iRetVal = CInt(InputBox("Enter no. of copies to print" & vbCr & vbCr & _
"Enter proper integer value between 1 and 3" & vbCr & _
"0 (zero) equals to Cancel", "No. of copies", "1"))
If iRetVal > 3 Then iRetVal = 3
Exit_GetNumberOfCopies:
GetNumberOfCopies = iRetVal
Exit Function
Err_GetNumberOfCopies:
Err.Clear
Resume 0
End Function
Use the same logic to get print option ;)

Remove line break

I want to remove the line break that I have in a certain text. I check in this forum how to do it and there were several answers but no one works for me at least in powerpoint.
I saw one example with left method:
If Len(myString) <> 0 Then
If Right$(myString, 2) = vbCrLf Or Right$(myString, 2) = vbNewLine Then
myString = Left$(myString, Len(myString) - 2)
End If
End If
text = Left (text, number) gives me Type mismatch error
text = Left$ (text, number) gives me compile error: Type-declaration character does not match declared data type.
I also try to replace the line break with "" but it just did nothing. It didn't gave me an error but the line break was still there.
The line break that I am using is vbCrLf
Your problem is likely that versions of PPT since 2007 don't use VBCrLf as a paragraph-ending character. This explains which versions use what characters for line or paragraph ends:
Paragraph endings and line breaks
http://www.pptfaq.com/FAQ00992_Paragraph_endings_and_line_breaks.htm
It's from the PPT FAQ site that I maintain.
For the object in which you want to remove the vbCrLf, try using
myObj.TextFrame.TextRange.Replace vbCrLf, ""
If you want to do this to a string (not an object) you can try something like this:
Sub stripStrings()
Dim longString As String
Dim stringCopy As String
longString = "first paragraph" & vbCrLf & "second paragraph" & vbCrLf & "third paragraph" & vbCrLf
stringCopy = Replace(longString, vbCrLf, "")
MsgBox "longstring is now:" & vbCrLf & longString
MsgBox "stringcopy is:" & vbCrLf & stringCopy
End Sub
As you will see, this removes the line breaks. Adapt for your purpose...
edit As Steve Rindsberg pointed out, it may be that your version of Powerpoint is using something other than vbCrLf as the paragraph delimiting character. Here is some code to help you figure this out - for each shape with text in it, it will extract the text, showing all "control characters" (ASCII value < 32) as \xnn where nn is the value of the control character (so that vbCR will display as \x13 for example):
Sub displayControlCharacters()
Dim sh As Shape
Dim t As String
For Each sh In ActivePresentation.Slides(1).Shapes
If sh.TextFrame.HasText Then
sh.Select
t = sh.TextFrame.TextRange.Text
MsgBox "The shape contains: " & vbCrLf & escapeString(t)
End If
Next sh
End Sub
Function escapeString(t As String)
Dim ii As Integer
Dim r As String
For ii = 1 To Len(t)
If Asc(Mid(t, ii, 1)) > 31 Then
r = r + Mid(t, ii, 1)
Else
r = r + "\x" + Format(Asc(Mid(t, ii, 1)), "0")
End If
Next
escapeString = r
End Function
A simple test showed that in PowerPoint 2010 you do have just \x13 at the end of a paragraph...