0

I am trying to pull text between two symbols:

S1 | STAR2449524 | XYZ Bank | 1 - Critical |Health Service Heartbeat Failure.

I need to extract | XYZ Bank |

Which is between 2'nd appearance of symbol and place it in my template where variable name is COMP1 |

Sub Reply_Test()

Dim origEmail As MailItem

Dim replyEmail As MailItem

Dim oRespond As Outlook.MailItem

Dim INC1 As String 'For Incident Number

Dim INo As Integer 'For Incident Number

Dim COMP1 As String 'For Company Name

Dim Com As Integer 'For Company Name
Dim ISSU1 As String ' For Issue

Dim Isu As Integer 'for Issue

Dim varSplit As Variant

'Dim msginfo As msg.Subject (Tried using not worked)

varSplit = Split("New incident |S1 | ICM1449524 | XYZ Bank | P1 - Critical |Health Service Heartbeat Failure.", "|")

'varSplit = Split(msginfo, "|") (Tried using not worked)

strSubject1 = varSplit(0)

strSubject2 = varSplit(1)

strSubject3 = varSplit(2)

strSubject4 = varSplit(3)

strSubject5 = varSplit(4)

Set origEmail = Application.ActiveWindow.Selection.Item(1)

Set replyEmail = Application.CreateItemFromTemplate("H:\Documents\test.oft")

replyEmail.To = origEmail.Reply.To

replyEmail.CC = "abc@xyz.com"

replyEmail.HTMLBody = replyEmail.HTMLBody & origEmail.Reply.HTMLBody

replyEmail.Subject = replyEmail.Subject & origEmail.Reply.Subject 

replyEmail.Subject = " <P1> - " & strSubject2 & " " & "For" & " " & strSubject3

replyEmail.Display

End Sub
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
RKVALU
  • 25
  • 5
  • In the HTMLBody, the text of interest is unlikely to be adjacent in the way your code assumes. It is very likely there will be Html tags in the way. Often the text body (property Body) is the Html body with all the tags removed and may be an easier source for the data you wish to extract. – Tony Dallimore Sep 08 '16 at 17:48
  • If you do not know what the bodies look like to a VBA macro, this [answer](http://stackoverflow.com/a/12146315/973283) of mine contains a macro which may help. – Tony Dallimore Sep 08 '16 at 17:52

1 Answers1

0

A an alternative to the macro suggested in my comment, you may find the one below more convenient. Add something like:

Debug.Print "=====Text====="
Debug.Print TidyTextForDspl(.Body)
Debug.Print "=====Html====="
Debug.Print TidyTextForDspl(.HTMLBody)
Debug.Print "=====End====="

to your existing macro.

Public Function TidyTextForDspl(ByVal Text As String) As String

  ' Tidy Text for dsplay by replacing white space with visible strings:
  '   Replace spaces by          {s} or {n s}
  '   Replace line feed by       {lf} or {n lf}
  '   Replace carriage return by {cr} or {n cr}
  '   Replace tab by             {tb} or {n tb}
  '   Replace non-break space by {nbs} or {n nbs}
  ' Where n is a count if the character repeats

  ' 15Mar16  Coded

  Dim InsStr As String
  Dim InxWsChar As Long
  Dim NumWsChar As Long
  Dim PosWsChar As Long
  Dim RetnVal As String
  Dim WsCharCrnt As Variant
  Dim WsCharValue As Variant
  Dim WsCharDspl As Variant

  WsCharValue = Array(" ", vbLf, vbCr, vbTab, Chr(160))
  WsCharDspl = Array("s", "lf", "cr", "tb", "nbs")

  RetnVal = Text
  For InxWsChar = LBound(WsCharValue) To UBound(WsCharValue)
    Do While True
      PosWsChar = InStr(1, RetnVal, WsCharValue(InxWsChar))
      If PosWsChar = 0 Then
        Exit Do
      End If
      NumWsChar = 1
      Do While Mid(RetnVal, PosWsChar + NumWsChar, 1) = WsCharValue(InxWsChar)
        NumWsChar = NumWsChar + 1
      Loop
      If NumWsChar = 1 Then
        InsStr = "{" & WsCharDspl(InxWsChar) & "}"
      Else
        InsStr = "{" & NumWsChar & WsCharDspl(InxWsChar) & "}"
      End If
      RetnVal = Mid(RetnVal, 1, PosWsChar - 1) & InsStr & Mid(RetnVal, PosWsChar + NumWsChar)
    Loop
  Next

  TidyTextForDspl = RetnVal

End Function

New section in response to question in comment

InStr is not the most useful function for your requirement. I recommend Split.
Split splits a string on a delimiter and returns the parts as an zero-based, one-dimensioned array.

The documentation says Split always returns a zero-based array and I have always found that to be true. However, there are functions that are affected by the Option Base statement so I always use the LBound function to be absolutely clear which element I am accessing.

This little macro uses Split to split your example string. I have used Trim to remove any leading or trailing spaces.

Option Explicit
Sub Test()

  Dim Inx As Long
  Dim Parts() As String

  Parts = Split("S1 | ICM21449524 | XYZ Bank | P1 - Critical |Health Service Heartbeat Failure", "|")

  For Inx = LBound(Parts) To UBound(Parts)
    Debug.Print Inx & " [" & Trim(Parts(Inx)) & "]"
  Next

End Sub

Second new section

You are not answering my question. Perhaps you do not understand its significance so I will give some demonstration code for the two most likely answers.

If you want a macro to process some emails, there are different ways of specifying which emails are to be processed.

One approach is for the user to select all the emails to be processed before starting the macro. If you click LeftMouse on an email, it is selected. If you then press and hold Shift while clicking Up or Down, you can select a block of contiguous emails. If you hold Ctrl while clicking LeftMouse on emails, you can select non-contiguous emails.

Select some emails and then run this macro:

Public Sub DemoExplorer()

  Dim Exp As Outlook.Explorer
  Dim ItemCrnt As MailItem
  Dim NumSelected As Long

  Set Exp = Outlook.Application.ActiveExplorer

  NumSelected = Exp.Selection.Count

  If NumSelected = 0 Then
    Debug.Print "No emails selected"
  Else
    For Each ItemCrnt In Exp.Selection
      With ItemCrnt
        Debug.Print "--------------------------"
        Debug.Print "From: " & .SenderName
        Debug.Print "Subject: " & .Subject
        Debug.Print "Received: " & Format(.ReceivedTime, "dMMMyy h:mm:ss")
      End With
    Next
  End If

End Sub

The above macro is one of my standard demonstration macros. It outputs a number of properties of each of the selected emails to the immediate window. You are only interested in Subject but I decided to leave the others for reference.

Another approach is for the user to move the emails to be processed to a special folder with a name such as “ToProcess”. The macro is coded to look at folder “ToProcess” and to process the emails within it. After the emails have been processed, they can be moved on to another folder with a name such as “Processed”. This is not an approach I favour so I have no code to demonstrate it. Instead I explain how to amend the next macro to match this approach.

My most used approach is to search down Inbox for new emails with specific characteristics. The macro processes these emails and then moves them to a “Processed” folder. This approach saves the user the bother of searching for the emails to be processed and moving them twice.

The code below expects to find a folder “Processed2” within the default Inbox. Either create folder “Processed2” within the default Inbox and run my code unchanged or amend my code so FolderDest2 references a folder of your choice. This code processes any email with a pipe, “|”, in the Subject. You will need to expand my code so only the required emails are processed.

Public Sub DemoSearch()

  Dim FolderDest2 As MAPIFolder
  Dim FolderDest1 As MAPIFolder
  Dim FolderSrc1 As MAPIFolder
  Dim FolderSrc2 As MAPIFolder
  Dim InxItemCrnt As Long
  Dim InxPart As Long
  Dim NS As Outlook.NameSpace
  Dim SubjectPart() As String

  Set NS = CreateObject("Outlook.Application").GetNamespace("MAPI")

  ' This is the easiest way to reference the default Inbox.
  ' However, you must be careful if, like me, you have multiple email addresses
  ' each with their own Inbox. The default Inbox may not be where you think it is.
  Set FolderSrc1 = NS.GetDefaultFolder(olFolderInbox)

  ' This references the Inbox in a specific PST or OST file.
  ' "tonydallimore23@gmail.com" is the user name that Outlook gave the OST file in
  ' which it stores emails sent to this account when I created the account. The user
  ' name is the name Output displays to the user. The file name on disk is different.
  Set FolderSrc2 = NS.Folders("tonydallimore23@gmail.com").Folders("Inbox")

  ' I do not know where you want to save processed emails. I have created
  ' FolderDest1 to show how to access a folder at the same level as Inbox
  ' but my code uses FolderDest2 which is a sub-folder of Inbox.

  ' This gets a reference to folder "Processed1" which is at the same level
  ' as the default Inbox.
  ' I have started at FolderSrc1 (Inbox) gone up one level to its parent
  ' (outlook data file) and doen to another child ("Processed1")
  Set FolderDest1 = FolderSrc1.Parent.Folders("Processed1")

  ' This gets a reference to folder "Processed2" which is a sub-folder of
  ' the default Inbox.
  Set FolderDest2 = FolderSrc1.Folders("Processed2")

  ' This examines the emails in reverse order.
  ' If I process email number 5 and then move it to another folder,
  ' the number of all subsequence emails is decreased by 1. If I looked at the
  ' emails in ascending sequence, email 6 would be ignored because it would have
  ' been renumbered wehn I looked for it. By looking at the emails in reverse
  ' sequence, I ensure email 6 has bee processed before the removal of email 5
  ' changes its number.

  ' I do not know how you identify the emails you want to process. I process
  ' any email with a pipe , "|", in the Subject

  For InxItemCrnt = FolderSrc1.Items.Count To 1 Step -1
    With FolderSrc1.Items.Item(InxItemCrnt)
      If .Class = olMail Then
        ' I am only interested in mail items.
        If .Subject <> "" Then
          ' ONlt attept split if there is a Subject
          SubjectPart = Split(.Subject, "|")
          If LBound(SubjectPart) <> UBound(SubjectPart) Then
            ' There is at least one pipe, "|", within the subject
            Debug.Print "====="
            Debug.Print "  Sender   " & .SenderEmailAddress
            Debug.Print "  Received " & Format(.ReceivedTime, "ddmmmyy hh:mm:ss")
            Debug.Print "  Subject: "
            For InxPart = LBound(SubjectPart) To UBound(SubjectPart)
              Debug.Print "    " & Trim(SubjectPart(InxPart))
            Next InxPart
            .Move FolderDest2
          End If  ' LBound(SubjectPart) <> UBound(SubjectPart)
        End If  ' .Subject <> ""
      End If  ' .Class = olMail
    End With  ' FolderSrc1.Items.Item(InxItemCrnt)
  Next InxItemCrnt

End Sub

If you prefer my second approach, you will need to amend the above code slightly. .Move FolderDest2, near the bottom, must be deleted. The statement near the top to specify the source folder will require amendment. I recommend you retain the code to identify emails to be processed in case the case accidentally move an inappropriate email to the source folder.

I hope running these two macros will fully explain the significance of my question. I wanted to only provide the code for the email selection method you preferred. I have now provided the code for the two major approach. Select whichever best meets your requirements as the basis for your macro.

Tony Dallimore
  • 12,335
  • 7
  • 32
  • 61
  • Hi Tony, Thank you for the above code. I have updated my original code which is working but its returning value after first character "|". i. e STAR2449524. I need to pull text between second and third appearance of character "|" i.e XYZ Bank. Please advise – RKVALU Sep 10 '16 at 07:14
  • @RKVALU Try the little macro I have added. I think it will provide the guidance you need. – Tony Dallimore Sep 10 '16 at 07:57
  • Hi Tony, I am a newbie in this. Could you please show me where to insert your code (Split) so i can get required output. – RKVALU Sep 10 '16 at 13:15
  • I cannot tell you how to update your code because I do not understand it. You have variables `INC1`, `INo` and so on but I am unsure how to relate them to the parts of the string. If "ICM21449524" is an incident number, `INC1 = Parts(1)` will move it to `INC1`. I do not understand what you are doing with the HTMLBody. – Tony Dallimore Sep 10 '16 at 19:11
  • quick question is it possible to split subject line using split function for every email with different subject line every time. Since every time subject changes with different incident number, client name and issue. – RKVALU Sep 22 '16 at 09:36
  • @RKVALU Your current code operates on the first selected email. You can loop through all the selected emails. You can loop down the Inbox looking for interesting emails. Each email you process will have its own subject which can be processed as required. – Tony Dallimore Sep 22 '16 at 13:52
  • as suggested by you I tried using split function i am able to achieve what is required but the result is only for 1 email. How can I declare subject common for all subject? I tried using msg.Subject but seems like it is only for vba excel. Please help. Below is the code for more clarity – RKVALU Sep 26 '16 at 11:08
  • @RKVALU. See my comment of Sep 22. Your code operates on the first or only selected email. Do you want to select more emails and have the macro process all of them? Do you want to look at every email in a folder? Either is possible but you must decide how to identify the emails to be processed. – Tony Dallimore Sep 26 '16 at 20:24
  • :- Yes, I get emails frequently with a different subject line but pattern resembles. So whenever I get an email i need to forward with the unique subject ( ICM# for XYZ Bank). So my concern is i need to assign a variable to my subject and splitting it using split function every time – RKVALU Sep 27 '16 at 09:50
  • just in case you want to see the code Dim varSplit As Variant 'Dim msginfo As msg.Subject (Tried using not worked) varSplit = Split("New incident | S1 | ICM21449524 | XYZ Bank | P1 - Critical |Health Service Heartbeat Failure.", "|") 'varSplit = Split(msginfo, "|") (Tried using not worked) strSubject1 = varSplit(0) strSubject2 = varSplit(1) strSubject3 = varSplit(2) strSubject4 = varSplit(3) strSubject5 = varSplit(4) replyEmail.Subject = " - " & strSubject2 & " " & "For" & " " & strSubject3 – RKVALU Sep 27 '16 at 10:01
  • You are not answering my question. I have added demonstration code to my answer that shows two different methods of processing multiple emails. – Tony Dallimore Sep 27 '16 at 23:03
  • @RKVALU. Forgot to add your user name to my last comment so you might not have been told about it. – Tony Dallimore Sep 28 '16 at 15:04
  • Thank you, Tony, Sorry but I guess you didn't understand my requirement. I get an email with a subject which has a pipe "|". So I need to split that into parts and respond to an email with the template attached to it. So My template will have ICM#, Company name, and issue. So when I split the subject into parts using the split function it will automatically assign parts with a sequence. So it would be easy for me to call the same on my subject by replacing some of the text on my default template using replace function. Hope this clears the doubt. – RKVALU Sep 29 '16 at 09:10
  • I have updated the original code. Please check and advise. – RKVALU Sep 29 '16 at 09:18
  • @RKVALU. Your current code only accesses the subject of single email. On 22 Sep, you stated you had many such emails and you needed to process each of them. My latest extension shows how to access many emails in three different ways, access each email's subject and split it into parts. I do not know how you want to locate the emails to be processed. Pick one of the approaches I have demonstrated and adapt it as necessary to become the structure for your macro. Where I output the parts of the subject to the Immediate Window, insert your code for creating the new email. – Tony Dallimore Sep 29 '16 at 09:22
  • (1) `Dim varSplit As Variant`. `varSplit` should be a dynamic array of strings. See my demonstration. (2) `Dim msginfo As msg.Subject ' (Tried using not worked)`. `msg.Subject` is not an VBA data type. Replace by `String`. – Tony Dallimore Sep 29 '16 at 09:27