Hello Access Group:
I'm trying to find a faster way to eliminate non-printable characters from a
memo field. I have an Access application that reads email from Outlook and
for certain messages saves the text of the message into a table in a Memo
field. The issue is that so many emails have embedded characters that if
copied straight to the memo field show up as black rectangles
(non-printable). It's not pretty sight when trying to read through the
jumble of black boxes.
So I was able to write a routine that loops through every character of the
email text and eliminates the non-printables by copying only valid characters
(character-by-character) to a variant data type, then when finished, copying
the variant to the table's memo field.
Here's a snippet of code
' ************************************************************
' Microsoft Access Code After Reading an Outlook Email Message
' ************************************************************
Dim varCleanBody As Variant
Dim i As Long
Dim intConvertedToOctal As Integer
' Note - EmailText is Defined As a Memo Field in a Table
' ****************************************************
' Scan Through Each Character Of An Email Message
' And Eliminate Non-Printing Characters
' (Keep CR/LF which is Octal 12 and 15)
' By Only Moving Printable Characters To varCleanBody
' Then moves the filtered results from varCleanBody
' to Table Field "EmailText" Which is Defined as Memo
' ****************************************************
varCleanBody = ""
For i = 1 To Len(Mailobject.Body)
intConvertedToOctal = Oct(Asc(Mid(Mailobject.Body, i, 1)))
If (intConvertedToOctal = 12 Or intConvertedToOctal = 15 Or _
intConvertedToOctal > 37) Then
varCleanBody = varCleanBody & Mid(Mailobject.Body, i, 1)
End If
Next i
recOut!EmailText = varCleanBody
This code works but it takes an extremely long time to run.
--
Rich Locus
Logicwurks, LLC
|
|
0
|
|
|
|
Reply
|
Utf
|
5/14/2010 6:26:01 AM |
|
Suggestions to make that code more efficient:
1. Operate on strings rather than variants.
2. Reduce the number of function calls.
3. Use Select Case as a way of defining the acceptable characters.
4. Declare your data types to match the functions you are calling (Longs
rather than integers here.)
Function PrintableOnly(ByVal strIn As String) As String
Dim i As Long
Dim strOut As String
Dim strChar As String
For i = 1& To Len(strIn)
strChar = Mid(strIn, i, 1&)
Select Case Asc(strChar)
Case 10, 13, Is >= 32
strOut = strOut & strChar
End Select
Next
PrintableOnly = strOut
End Function
--
Allen Browne - Microsoft MVP. Perth, Western Australia
Tips for Access users - http://allenbrowne.com/tips.html
Reply to group, rather than allenbrowne at mvps dot org.
"Rich Locus" <RichLocus@discussions.microsoft.com> wrote in message
news:11B55DFB-71EB-4F2B-96B5-6A34405790D4@microsoft.com...
> Hello Access Group:
>
> I'm trying to find a faster way to eliminate non-printable characters from
> a
> memo field. I have an Access application that reads email from Outlook
> and
> for certain messages saves the text of the message into a table in a Memo
> field. The issue is that so many emails have embedded characters that if
> copied straight to the memo field show up as black rectangles
> (non-printable). It's not pretty sight when trying to read through the
> jumble of black boxes.
>
> So I was able to write a routine that loops through every character of the
> email text and eliminates the non-printables by copying only valid
> characters
> (character-by-character) to a variant data type, then when finished,
> copying
> the variant to the table's memo field.
>
> Here's a snippet of code
>
> ' ************************************************************
> ' Microsoft Access Code After Reading an Outlook Email Message
> ' ************************************************************
> Dim varCleanBody As Variant
> Dim i As Long
> Dim intConvertedToOctal As Integer
> ' Note - EmailText is Defined As a Memo Field in a Table
>
> ' ****************************************************
> ' Scan Through Each Character Of An Email Message
> ' And Eliminate Non-Printing Characters
> ' (Keep CR/LF which is Octal 12 and 15)
> ' By Only Moving Printable Characters To varCleanBody
> ' Then moves the filtered results from varCleanBody
> ' to Table Field "EmailText" Which is Defined as Memo
> ' ****************************************************
> varCleanBody = ""
> For i = 1 To Len(Mailobject.Body)
> intConvertedToOctal = Oct(Asc(Mid(Mailobject.Body, i, 1)))
> If (intConvertedToOctal = 12 Or intConvertedToOctal = 15 Or _
> intConvertedToOctal > 37) Then
> varCleanBody = varCleanBody & Mid(Mailobject.Body, i, 1)
> End If
> Next i
> recOut!EmailText = varCleanBody
>
> This code works but it takes an extremely long time to run.
> --
> Rich Locus
> Logicwurks, LLC
|
|
0
|
|
|
|
Reply
|
Allen
|
5/14/2010 8:13:25 AM
|
|
And, now that it's cleaned up, you probably want to
include 9 as well as 10 and 13:
Case 9, 10, 13, Is >= 32
9 is the tab character, and it is printable.
(david)
"Allen Browne" <AllenBrowne@SeeSig.Invalid> wrote in message
news:ODLTU1z8KHA.5476@TK2MSFTNGP06.phx.gbl...
> Suggestions to make that code more efficient:
> 1. Operate on strings rather than variants.
> 2. Reduce the number of function calls.
> 3. Use Select Case as a way of defining the acceptable characters.
> 4. Declare your data types to match the functions you are calling (Longs
> rather than integers here.)
>
> Function PrintableOnly(ByVal strIn As String) As String
> Dim i As Long
> Dim strOut As String
> Dim strChar As String
>
> For i = 1& To Len(strIn)
> strChar = Mid(strIn, i, 1&)
> Select Case Asc(strChar)
> Case 10, 13, Is >= 32
> strOut = strOut & strChar
> End Select
> Next
> PrintableOnly = strOut
> End Function
>
> --
> Allen Browne - Microsoft MVP. Perth, Western Australia
> Tips for Access users - http://allenbrowne.com/tips.html
> Reply to group, rather than allenbrowne at mvps dot org.
>
>
> "Rich Locus" <RichLocus@discussions.microsoft.com> wrote in message
> news:11B55DFB-71EB-4F2B-96B5-6A34405790D4@microsoft.com...
>> Hello Access Group:
>>
>> I'm trying to find a faster way to eliminate non-printable characters
>> from a
>> memo field. I have an Access application that reads email from Outlook
>> and
>> for certain messages saves the text of the message into a table in a Memo
>> field. The issue is that so many emails have embedded characters that if
>> copied straight to the memo field show up as black rectangles
>> (non-printable). It's not pretty sight when trying to read through the
>> jumble of black boxes.
>>
>> So I was able to write a routine that loops through every character of
>> the
>> email text and eliminates the non-printables by copying only valid
>> characters
>> (character-by-character) to a variant data type, then when finished,
>> copying
>> the variant to the table's memo field.
>>
>> Here's a snippet of code
>>
>> ' ************************************************************
>> ' Microsoft Access Code After Reading an Outlook Email Message
>> ' ************************************************************
>> Dim varCleanBody As Variant
>> Dim i As Long
>> Dim intConvertedToOctal As Integer
>> ' Note - EmailText is Defined As a Memo Field in a Table
>>
>> ' ****************************************************
>> ' Scan Through Each Character Of An Email Message
>> ' And Eliminate Non-Printing Characters
>> ' (Keep CR/LF which is Octal 12 and 15)
>> ' By Only Moving Printable Characters To varCleanBody
>> ' Then moves the filtered results from varCleanBody
>> ' to Table Field "EmailText" Which is Defined as Memo
>> ' ****************************************************
>> varCleanBody = ""
>> For i = 1 To Len(Mailobject.Body)
>> intConvertedToOctal = Oct(Asc(Mid(Mailobject.Body, i, 1)))
>> If (intConvertedToOctal = 12 Or intConvertedToOctal = 15 Or _
>> intConvertedToOctal > 37) Then
>> varCleanBody = varCleanBody & Mid(Mailobject.Body, i, 1)
>> End If
>> Next i
>> recOut!EmailText = varCleanBody
>>
>> This code works but it takes an extremely long time to run.
>> --
>> Rich Locus
>> Logicwurks, LLC
>
|
|
0
|
|
|
|
Reply
|
david
|
5/14/2010 11:21:51 AM
|
|
I would give a try to a double index run, in order to create a lot of
strings (trough concatenation in a loop).
Function PrintableOnly(ByVal strIn As String) As String
Dim i As Long ' where I am to read
Dim j as Long ' where I am to write
' Dim strOut As String
Dim strChar As String
j = 0 ' intialize explicitly (not required but for completeness)
For i = 1& To Len(strIn)
strChar = Mid$(strIn, i, 1&)
Select Case Asc(strChar)
Case 9, 10, 13, Is >= 32
j=j+1
Mid$(strIn, j, 1) = strChar
End Select
Next
PrintableOnly = Left$(strIn, j ) ' shorter string, now
End Function
The advantage is that is uses only one string, ever (Concatenation trough a
loop may end up by exceeding the reserved space, buffer, and force another
string creation). Note that when the character is not printable, j is not
increased, so the next position to be filled, j+1, is still 'free' to accept
the next printable character (or CR, LF), which makes the algorithm like
sliding one character at a time, into proper place. I also use the $ string
function to avoid possible VBA automatic casting to 'variant'.
The ByVal is important, in the argument, else, the original string would
have been modified, but if the original string does not matter, you may save
few micro seconds by using ByRef instead (and while you are at it, change
the Function to a Sub, since the result will be the 'initial variable' which
would have been modified... but those micro optimizations are probably
without human perceptible effect as runtime execution is concerned, and too
error prone if used in another context, without remembering all the involved
details).
Vanderghast, Access MVP
"david" <david@nospam.nospam> wrote in message
news:O3O7ne18KHA.1892@TK2MSFTNGP05.phx.gbl...
> And, now that it's cleaned up, you probably want to
> include 9 as well as 10 and 13:
>
> Case 9, 10, 13, Is >= 32
>
> 9 is the tab character, and it is printable.
>
> (david)
>
>
> "Allen Browne" <AllenBrowne@SeeSig.Invalid> wrote in message
> news:ODLTU1z8KHA.5476@TK2MSFTNGP06.phx.gbl...
>> Suggestions to make that code more efficient:
>> 1. Operate on strings rather than variants.
>> 2. Reduce the number of function calls.
>> 3. Use Select Case as a way of defining the acceptable characters.
>> 4. Declare your data types to match the functions you are calling (Longs
>> rather than integers here.)
>>
>> Function PrintableOnly(ByVal strIn As String) As String
>> Dim i As Long
>> Dim strOut As String
>> Dim strChar As String
>>
>> For i = 1& To Len(strIn)
>> strChar = Mid(strIn, i, 1&)
>> Select Case Asc(strChar)
>> Case 10, 13, Is >= 32
>> strOut = strOut & strChar
>> End Select
>> Next
>> PrintableOnly = strOut
>> End Function
>>
>> --
>> Allen Browne - Microsoft MVP. Perth, Western Australia
>> Tips for Access users - http://allenbrowne.com/tips.html
>> Reply to group, rather than allenbrowne at mvps dot org.
>>
>>
>> "Rich Locus" <RichLocus@discussions.microsoft.com> wrote in message
>> news:11B55DFB-71EB-4F2B-96B5-6A34405790D4@microsoft.com...
>>> Hello Access Group:
>>>
>>> I'm trying to find a faster way to eliminate non-printable characters
>>> from a
>>> memo field. I have an Access application that reads email from Outlook
>>> and
>>> for certain messages saves the text of the message into a table in a
>>> Memo
>>> field. The issue is that so many emails have embedded characters that
>>> if
>>> copied straight to the memo field show up as black rectangles
>>> (non-printable). It's not pretty sight when trying to read through the
>>> jumble of black boxes.
>>>
>>> So I was able to write a routine that loops through every character of
>>> the
>>> email text and eliminates the non-printables by copying only valid
>>> characters
>>> (character-by-character) to a variant data type, then when finished,
>>> copying
>>> the variant to the table's memo field.
>>>
>>> Here's a snippet of code
>>>
>>> ' ************************************************************
>>> ' Microsoft Access Code After Reading an Outlook Email Message
>>> ' ************************************************************
>>> Dim varCleanBody As Variant
>>> Dim i As Long
>>> Dim intConvertedToOctal As Integer
>>> ' Note - EmailText is Defined As a Memo Field in a Table
>>>
>>> ' ****************************************************
>>> ' Scan Through Each Character Of An Email Message
>>> ' And Eliminate Non-Printing Characters
>>> ' (Keep CR/LF which is Octal 12 and 15)
>>> ' By Only Moving Printable Characters To varCleanBody
>>> ' Then moves the filtered results from varCleanBody
>>> ' to Table Field "EmailText" Which is Defined as Memo
>>> ' ****************************************************
>>> varCleanBody = ""
>>> For i = 1 To Len(Mailobject.Body)
>>> intConvertedToOctal = Oct(Asc(Mid(Mailobject.Body, i, 1)))
>>> If (intConvertedToOctal = 12 Or intConvertedToOctal = 15 Or _
>>> intConvertedToOctal > 37) Then
>>> varCleanBody = varCleanBody & Mid(Mailobject.Body, i, 1)
>>> End If
>>> Next i
>>> recOut!EmailText = varCleanBody
>>>
>>> This code works but it takes an extremely long time to run.
>>> --
>>> Rich Locus
>>> Logicwurks, LLC
>>
>
>
|
|
0
|
|
|
|
Reply
|
vanderghast
|
5/14/2010 1:26:42 PM
|
|
To All of you that helped, THANKS! These are good suggestions and I'm going
to run with them.
--
Rich Locus
Logicwurks, LLC
"Allen Browne" wrote:
> Suggestions to make that code more efficient:
> 1. Operate on strings rather than variants.
> 2. Reduce the number of function calls.
> 3. Use Select Case as a way of defining the acceptable characters.
> 4. Declare your data types to match the functions you are calling (Longs
> rather than integers here.)
>
> Function PrintableOnly(ByVal strIn As String) As String
> Dim i As Long
> Dim strOut As String
> Dim strChar As String
>
> For i = 1& To Len(strIn)
> strChar = Mid(strIn, i, 1&)
> Select Case Asc(strChar)
> Case 10, 13, Is >= 32
> strOut = strOut & strChar
> End Select
> Next
> PrintableOnly = strOut
> End Function
>
> --
> Allen Browne - Microsoft MVP. Perth, Western Australia
> Tips for Access users - http://allenbrowne.com/tips.html
> Reply to group, rather than allenbrowne at mvps dot org.
>
>
> "Rich Locus" <RichLocus@discussions.microsoft.com> wrote in message
> news:11B55DFB-71EB-4F2B-96B5-6A34405790D4@microsoft.com...
> > Hello Access Group:
> >
> > I'm trying to find a faster way to eliminate non-printable characters from
> > a
> > memo field. I have an Access application that reads email from Outlook
> > and
> > for certain messages saves the text of the message into a table in a Memo
> > field. The issue is that so many emails have embedded characters that if
> > copied straight to the memo field show up as black rectangles
> > (non-printable). It's not pretty sight when trying to read through the
> > jumble of black boxes.
> >
> > So I was able to write a routine that loops through every character of the
> > email text and eliminates the non-printables by copying only valid
> > characters
> > (character-by-character) to a variant data type, then when finished,
> > copying
> > the variant to the table's memo field.
> >
> > Here's a snippet of code
> >
> > ' ************************************************************
> > ' Microsoft Access Code After Reading an Outlook Email Message
> > ' ************************************************************
> > Dim varCleanBody As Variant
> > Dim i As Long
> > Dim intConvertedToOctal As Integer
> > ' Note - EmailText is Defined As a Memo Field in a Table
> >
> > ' ****************************************************
> > ' Scan Through Each Character Of An Email Message
> > ' And Eliminate Non-Printing Characters
> > ' (Keep CR/LF which is Octal 12 and 15)
> > ' By Only Moving Printable Characters To varCleanBody
> > ' Then moves the filtered results from varCleanBody
> > ' to Table Field "EmailText" Which is Defined as Memo
> > ' ****************************************************
> > varCleanBody = ""
> > For i = 1 To Len(Mailobject.Body)
> > intConvertedToOctal = Oct(Asc(Mid(Mailobject.Body, i, 1)))
> > If (intConvertedToOctal = 12 Or intConvertedToOctal = 15 Or _
> > intConvertedToOctal > 37) Then
> > varCleanBody = varCleanBody & Mid(Mailobject.Body, i, 1)
> > End If
> > Next i
> > recOut!EmailText = varCleanBody
> >
> > This code works but it takes an extremely long time to run.
> > --
> > Rich Locus
> > Logicwurks, LLC
>
> .
>
|
|
0
|
|
|
|
Reply
|
Utf
|
5/14/2010 8:25:01 PM
|
|
Thanks again:
For All of you that helped me redesign the non-printable character stripper,
the time for a typical run went from 10 minutes down to 2 seconds... amazing.
Here's the final code with your suggestions. It reads all mail in the
Outlook Inbox, and for those items with a subject line of "Client" adds the
mail to a database table after it has cleaned the non-printables in the
message body. It moves the mail from the inbox to one of two other
historical folders.
Option Compare Database
Option Explicit
Public Function ReadInboxAndMoveWithCharReplaceV3()
Dim TempRst As DAO.Recordset
Dim OlApp As Outlook.Application
Dim Inbox As Outlook.MAPIFolder
Dim SavedMailFolder As Outlook.MAPIFolder
Dim RejectMailFolder As Outlook.MAPIFolder
Dim InboxItems As Outlook.Items
Dim SavedMailItems As Outlook.MailItem
Dim RejectMailItems As Outlook.MailItem
Dim Mailobject As Object
Dim db As DAO.Database
Dim i As Long
'DoCmd.SetWarnings False
'DoCmd.RunSQL "Delete * from tbl_outlooktemp"
'DoCmd.SetWarnings True
Set db = CurrentDb
Set OlApp = CreateObject("Outlook.Application")
Set Inbox = OlApp.GetNamespace("Mapi").GetDefaultFolder(olFolderInbox)
Set SavedMailFolder =
OlApp.GetNamespace("Mapi").GetDefaultFolder(olFolderInbox).Parent.Folders("Saved Mail")
Set RejectMailFolder =
OlApp.GetNamespace("Mapi").GetDefaultFolder(olFolderInbox).Parent.Folders("Rejects")
Set TempRst = CurrentDb.OpenRecordset("tbl_OutlookTemp")
'
Set InboxItems = Inbox.Items
dteUpdateTime = Date + Time
intUpdateCount = 0
For i = InboxItems.Count To 1 Step -1
Set Mailobject = InboxItems(i)
If UCase(Left(Mailobject.Subject, 6)) <> "CLIENT" Then
Mailobject.UnRead = False
Set SavedMailItems = Mailobject.Move(RejectMailFolder)
intUpdateCount = intUpdateCount + 1
Else
With TempRst
.AddNew
!Subject = Mailobject.Subject
!from = Mailobject.SenderName
!To = Mailobject.To
!Body = PrintableOnly(Mailobject.Body)
!DateSent = Mailobject.SentOn
.Update
Mailobject.UnRead = False
Set SavedMailItems = Mailobject.Move(SavedMailFolder)
intUpdateCount = intUpdateCount + 1
End With
End If
Next
Set TempRst = Nothing
Set OlApp = Nothing
Set Inbox = Nothing
Set SavedMailFolder = Nothing
Set InboxItems = Nothing
Set SavedMailItems = Nothing
Set Mailobject = Nothing
End Function
Function PrintableOnly(ByVal strIn As String) As String
Dim i As Long ' where I am to read
Dim j As Long ' where I am to write
Dim strChar As String
j = 0 ' intialize explicitly (not required but for completeness)
For i = 1& To Len(strIn)
strChar = Mid$(strIn, i, 1&)
Select Case Asc(strChar)
Case 10, 13, Is >= 32
j = j + 1
Mid$(strIn, j, 1) = strChar
End Select
Next
PrintableOnly = Left$(strIn, j) ' shorter string, now
End Function
--
Rich Locus
Logicwurks, LLC
"Rich Locus" wrote:
> Hello Access Group:
>
> I'm trying to find a faster way to eliminate non-printable characters from a
> memo field. I have an Access application that reads email from Outlook and
> for certain messages saves the text of the message into a table in a Memo
> field. The issue is that so many emails have embedded characters that if
> copied straight to the memo field show up as black rectangles
> (non-printable). It's not pretty sight when trying to read through the
> jumble of black boxes.
>
> So I was able to write a routine that loops through every character of the
> email text and eliminates the non-printables by copying only valid characters
> (character-by-character) to a variant data type, then when finished, copying
> the variant to the table's memo field.
>
> Here's a snippet of code
>
> ' ************************************************************
> ' Microsoft Access Code After Reading an Outlook Email Message
> ' ************************************************************
> Dim varCleanBody As Variant
> Dim i As Long
> Dim intConvertedToOctal As Integer
> ' Note - EmailText is Defined As a Memo Field in a Table
>
> ' ****************************************************
> ' Scan Through Each Character Of An Email Message
> ' And Eliminate Non-Printing Characters
> ' (Keep CR/LF which is Octal 12 and 15)
> ' By Only Moving Printable Characters To varCleanBody
> ' Then moves the filtered results from varCleanBody
> ' to Table Field "EmailText" Which is Defined as Memo
> ' ****************************************************
> varCleanBody = ""
> For i = 1 To Len(Mailobject.Body)
> intConvertedToOctal = Oct(Asc(Mid(Mailobject.Body, i, 1)))
> If (intConvertedToOctal = 12 Or intConvertedToOctal = 15 Or _
> intConvertedToOctal > 37) Then
> varCleanBody = varCleanBody & Mid(Mailobject.Body, i, 1)
> End If
> Next i
> recOut!EmailText = varCleanBody
>
> This code works but it takes an extremely long time to run.
> --
> Rich Locus
> Logicwurks, LLC
|
|
0
|
|
|
|
Reply
|
Utf
|
5/14/2010 10:48:01 PM
|
|
|
5 Replies
196 Views
(page loaded in 2.311 seconds)
Similiar Articles: Typing text is impossibly slow in text boxes when in publishing ...Publishing Layout View requires very powerful hardware, and even then it tends to ... that both OS X and Office 2008 are completely updated: they will be extremely slow ... Database running so slow? - microsoft.public.accessAre all fields used as criteria or for sorting indexed? ... Database running very slow ... my database run fast on my ... Why is my Access database slow over the network? Bytes Per Row - microsoft.public.access.queries- Some field types are just addresses (e.g. a memo, hyperlink, and ... user filled up all the fields, you could programmatically loop through ... but inserting rows is very slow ... Asset tracking design problem using MS Access 2007 - microsoft ...Employee Barcode scan IN and OUT using Access 2007 ... MS Access start up: very slow - microsoft.public.access ... ... values, maintenance schedules, and depreciation over ... Masterdocument does not save format changes - microsoft.public.mac ...Word will slow down a bit, but it won't break ... use separate files and INCLUDETEXT fields. Here is part of a VERY old ... default, format, change Hello: After scanning the ... MmAllocateContiguousMemory and non-paged pool size - microsoft ...It doesn't take very long for chaos to take over, so that dozens of ... but the better question is why you want to scan ... 1M = buffer), and sorry, but PPM is so slow ... Norton Internet Security 2010 compatibility problem? - microsoft ...All the big complaints, such as slow install, even ... Otherwise the products (NIS, NAV, N360) have been very ... But techs who actually work in this field agree with me. Is this Regular Expression for UTF-8 Correct?? - microsoft.public ...--=_mimegpg-commodore.email-scan.com-18468-1273792367-0002 ... of handling the character set are pervasive and very ... I can see through this ruse now, so there is no sense in ... Re: Scanning Through "Memo" Field Is Very SlowRe: Scanning Through "Memo" Field Is Very Slow Tech-Archive recommends: Repair Windows Errors & Optimize Windows Performance wbir.com | Knoxville, TN - Knoxville, Tennessee | Knoxville News ...2-year-old in intensive care after being accidentally backed over by grandfather Electromagnetic Radiation: Field Memo - Occupational Safety and ...Once you make it through the material one time, it ... In the reactive near-field (very close to the antenna ... A follow up field service memo, to be issued at a later date ... Filtering Question: filter, foxpro, set - Experts Exchange - Your ...I find them slow. I seek a record ... Also, my experience is that a memo field can get corrupted if you make a pass through ... needs to do a complex filter, scan ... Access Database Too Slow - Make Faster! - Access Programmers ...Do not use memo fields if at all possible - they can cause ... Normalize the table but don't over normalize it ... the database folder from active virus protection scanning. 7/22/2012 10:42:52 AM
|