When I parse through an email that looks like:
included_po~301993959 'VBCRLF
po_no~vendor~part_no~class~type_code~buyer~qty_ordered~measure~balance_on_order~cost~amt_ordered~order_date~delivery_date~ship_Date~receive_date~open~wo_no 'VBCRLF
301993959~100000~88008K~PROBE 800~F~VAX~4.0 ~EA~4.0~100.3300~401.32000~011513~012313~012313~000000~Y~STOCK 'VBCRLF
301993959~100000~TFCI-010-50~WIRE SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~STOCK 'VBCRLF
301993959~100000~TFIR-010-50~WIRE SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~STOCK 'VBCRLF
using code:
Public Sub AddItems()
Dim aLineItem() As String
Dim aItem() As String
Dim i As Integer
Dim j As Integer
Dim iCnt As Double
Dim msg
Dim Item As Items
ReDim sWo(0)
iCnt = 0
For i = 1 To UBound(sMsg())
aLineItem = Split(sMsg(i), vbCrLf)
For j = 1 To UBound(aLineItem)
If aLineItem(j) <> "" Then
If blah = 1 Then
Debug.Print ("...." & aLineItem(j))
End If
aItem = Split(aLineItem(j), "~")
If (aItem(0) <> "") And (aItem(0) <> "included_po") And (aItem(0) <> "po_no") Then
Item.PO_num = GetWo(aItem(1))
If Item.PO_num <> "0" Then
Item.Company = aItem(1)
Item.Delivery_date = aItem(12)
Item.pn = aItem(2)
Item.QTY_ordered = aItem(6)
Item.Unit_Price = aItem(9)
End If 'If Item.PO_num <> "0" Then
End If 'If aItem(1) <> "" Then
End If ' If aLineItem(j) <> "" Then
Next j
Next i
End Sub
The email parsing looks like this:
....301993959~100000~88008K~PROBE
....8800~F~VAX~4.0~EA~4.0~100.3300~401.32000~011513~012313~012313~000000~Y~S
....TOCK
Is there a better way to parse this email?
EDIT #1:
Public Sub GetMailMsg()
Dim pop3 As jmail.pop3
Dim iCount As Integer
Dim i As Integer
Dim mailID As Integer
Dim j As Integer
Dim sSubject As String
j = 0
ReDim sMsg(0)
'connect to the mail box
Set pop3 = New pop3
pop3.Connect "REMOVED FOR SECURITY"
'Get message count
iCount = pop3.Count
'Read Messages
For i = 1 To iCount
sSubject = pop3.Messages.Item(i).Subject
Label1.Caption = "Reading message.." & sSubject
DoEvents
If InStr(sSubject, "China Purchase Orders") <> 0 Then 'email test
j = j + 1
ReDim Preserve sMsg(j)
sMsg(j) = pop3.Messages.Item(i).Body
Label1.Caption = "Reading mail message for order " & sSubject
If blah = 1 Then
Debug.Print ("Reading mail message for order " & sSubject)
Debug.Print ("Reading mail message for order " & sMsg(j))
End If
End If
Next
pop3.Disconnect
Set pop3 = Nothing
End SUb
--EDIT #2
OUTPUT FROM DEBUG:
Reading mail message for order China Purchase Orders
Reading mail message for order
included_po~301993959
po_no~vendor~part_no~class~type_code~buyer~qty_ordered~measure~balance_o 'VBCRLF
n_order~cost~amt_ordered~order_date~delivery_date~ship_Date~receive_date 'VBCRLF
~open~wo_no 'VBCRLF
301993959~100000~88008K~PROBE 'VBCRLF
8800~F~VAX~4.0~EA~4.0~100.3300~401.32000~011513~012313~012313~000000~Y~S 'VBCRLF
TOCK 'VBCRLF
301993959~100000~TFCI-010-50~WIRE 'VBCRLF
SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~ST 'VBCRLF
OCK 'VBCRLF
301993959~100000~TFIR-010-50~WIRE 'VBCRLF
SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~ST 'VBCRLF
OCK 'VBCRLF
Your lines aren't breaking up properly makes me think there is a problem in the line aLineItem = Split(sMsg(i), vbCrLf). Please check whether you don't have any vbCrLF in the line you aren't getting right.
Is that line one continuous line?
Edit #1 # Jan 16, 2013 1:16pm EST:
I created a file and pasted provided input.
I created a simple program and incorporated your code into it. Please see produced DEBUG below, consisting as expected with 3 lines beginning with 301993959 and ending with STOCK. This is the correct and desirable output, right?
....301993959~100000~TFCI-010-50~WIRE SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~STOCK
....301993959~100000~TFIR-010-50~WIRE SPTEF~F~VAX~1.0~SP~1.0~12.6400~12.64000~011513~012313~012313~000000~Y~STOCK
....301993959~100000~88008K~PROBE 800~F~VAX~4.0 ~EA~4.0~100.3300~401.32000~011513~012313~012313~000000~Y~STOCK
So the code you provided is working fine. If you say the input file is fine too, that means the issue is with how you are reading that email, specifically how you populate sMsg(). Can you post that code please?
Edit #2 # Jan 16, 2013 2:32pm EST:
You are getting some unwanted vbCrLfs in your single record line and you can't split it the way you want. Here is what I suggest you do:
1) If you can modify GetMailMsg to instead of loading Body as it is, go through line by line to avoid generating unwanted vbCrLfs. I have zero experience with pop objects so I don't know if that is possible.
2) If the number of unwanted cbCrLfs is consistent, ex: 2 in a single record, then you can simply adjust your code to concatenate split records like this
DIM concatLine As String
For j = 1 To UBound(aLineItem) Step 3
concatLine = aLineItem(j) & aLineItem(j+1) & aLineItem(j+2)
If concatLine <> "" Then
If blah = 1 Then
Debug.Print ("...." & concatLine)
End If
aItem = Split(concatLine, "~")
If (aItem(0) <> "") And (aItem(0) <> "included_po") And (aItem(0) <> "po_no") Then
Item.PO_num = GetWo(aItem(1))
If Item.PO_num <> "0" Then
Item.Company = aItem(1)
Item.Delivery_date = aItem(12)
Item.pn = aItem(2)
Item.QTY_ordered = aItem(6)
Item.Unit_Price = aItem(9)
End If 'If Item.PO_num <> "0" Then
End If 'If aItem(1) <> "" Then
End If ' If concatLine <> "" Then
Next j
3) or better yet, concat string until you reach the end of the record and then split that concatenated string.
DIM concatLine As String
DIM detailsRecord as Integer
For detailsRecord = 1 To UBound(aLineItem)
if LCase(Right(aLineItem(detailsRecord),5)) = 'wo_no' Then Exit For ' when we find this tag, we know where details record begin
Next detailsRecord
For j = detailsRecord + 1 To UBound(aLineItem) ' begin looping detail records
concatLine = concatLine + aLineItem(j)
If UCase(Right(aLineItem(j), 5)) = "STOCK" Then ' this is your end of the record indicator
If blah = 1 Then
Debug.Print ("...." & concatLine)
End If
aItem = Split(concatLine, "~")
If (aItem(0) <> "") Then
Item.PO_num = GetWo(aItem(1))
If Item.PO_num <> "0" Then
Item.Company = aItem(1)
Item.Delivery_date = aItem(12)
Item.pn = aItem(2)
Item.QTY_ordered = aItem(6)
Item.Unit_Price = aItem(9)
End If 'If Item.PO_num <> "0" Then
End If 'If aItem(1) <> "" Then
End If ' If concatLine <> "" Then
concatLine = ""
Next j
For cases 2 and 3, don't forget to handle the headers first- you will have to move If (aItem(0) <> "") And (aItem(0) <> "included_po") And (aItem(0) <> "po_no") outside the main loop to handle header records (i believe the first 2 or records are headers).
EDIT #3:
I fixed scenario #3 to skip through the header records (assuming 'wo_no' is an indicator of the end of that record), then to concatenate strings to form a single record by searching for an end tag ("STOCK"). This method is going to be flexible enough to handle dynamic number of vbCrLfs in the email body that splits a single record into unpredictable number of strings.
The code was typed in the browser, so I don't guarantee it will work :)
Since you know what should start each line, then use the Split function using "301993959".
Dim LineItems(100) As String
x = Split(sMsg(i), "301993959")
For j = 1 To UBound(x) - 1 'Don't use 0 becuase you don't need that part
LineItems(j - 1) = x(j)
Next i
Of Course you could take it one step further by then splitting each item in the string using "~" as your second delimiter.
Dim LineItems(100, 15) As String
x = Split(Text1.Text, "301993959")
For j = 1 To UBound(x) - 1 'Don't use 0 becuase you don't need that part
y = Split(x(j), "~")
For k = 1 To 15
LineItems(j - 1, k) = y(k)
Next k
Next j
Related
I'm creating a database in ms-access 2016, I want to set a field to email address that only accepts institutional e-mail address excluding such as Gmail, yahoo, Hotmail...etc, if user has entered such an e-mail address as above then the warning or error message be showed to enter correct value.
How can I do it?
You can use the function below in the BeforeUpdate event of the textbox:
Cancel = Not IsMailAddress(Nz(Me!YourTextbox.Value))
If Cancel = True Then
MessageBox "Please enter a valid e-mail address."
End If
and the function:
Public Function IsEmailAddress( _
ByVal strEmailAddresses As String) _
As Boolean
' Checks if strEMailAddr could represent one or more valid e-mail addresses.
' Does not check validity of domain names.
'
' 2003-06-22. Cactus Data ApS, CPH
' 2018-12-01. Expanded to allow for and validate multiple addresses.
' Allowed characters.
Const cstrValidChars As String = "#_-.0123456789abcdefghijklmnopqrstuvwxyz"
Const cstrDot As String = "."
Const cstrAt As String = "#"
' Minimum length of an e-mail address (a#a.ca).
Const cintAddressLenMin As Integer = 6
' Address separator.
Const cstrSeparator As String = ";"
Dim avarAddresses As Variant
Dim Index As Integer
Dim strEmailAddr As String
Dim strValidChars As String
Dim booFailed As Boolean
Dim intPos As Integer
Dim intI As Integer
avarAddresses = Split(strEmailAddresses, cstrSeparator)
For Index = LBound(avarAddresses) To UBound(avarAddresses)
strEmailAddr = avarAddresses(Index)
' Strip a display name.
CleanEmailAddress strEmailAddr
' Convert to lowercase.
strEmailAddr = LCase(strEmailAddr)
' Check that strEMailAddr contains allowed characters only.
For intI = 1 To Len(strEmailAddr)
If InStr(cstrValidChars, Mid(strEmailAddr, intI, 1)) = 0 Then
booFailed = True
End If
Next
If booFailed = False Then
' Check that the first character is not cstrAt.
booFailed = Left(strEmailAddr, 1) = cstrAt
If booFailed = False Then
' Check that the first character is not a cstrDot.
booFailed = Left(strEmailAddr, 1) = cstrDot
If booFailed = False Then
' Check that length of strEMailAddr exceeds
' minimum length of an e-mail address.
intPos = Len(strEmailAddr)
booFailed = (intPos < cintAddressLenMin)
If booFailed = False Then
' Check that none of the last two characters of strEMailAddr is a dot.
booFailed = (InStr(intPos - 1, strEmailAddr, cstrDot) > 0)
If booFailed = False Then
' Check that strEMailAddr does contain a cstrAt.
intPos = InStr(strEmailAddr, cstrAt)
booFailed = (intPos = 0)
If booFailed = False Then
' Check that strEMailAddr does contain one cstrAt only.
booFailed = (InStr(intPos + 1, strEmailAddr, cstrAt) > 0)
If booFailed = False Then
' Check that the character leading cstrAt is not cstrDot.
booFailed = (Mid(strEmailAddr, intPos - 1, 1) = cstrDot)
If booFailed = False Then
' Check that the character following cstrAt is not cstrDot.
booFailed = (Mid(strEmailAddr, intPos + 1, 1) = cstrDot)
If booFailed = False Then
' Check that strEMailAddr contains at least one cstrDot
' following the sign after cstrAt.
booFailed = Not (InStr(intPos, strEmailAddr, cstrDot) > 1)
End If
End If
End If
End If
End If
End If
End If
End If
End If
If booFailed = True Then
Exit For
End If
Next
IsEmailAddress = Not booFailed
End Function
I have an issue where only the last record in a csv file is written to the database by my stored procedure. I thought this might be related to the type of file (csv or text) because I have a comma delimited text file with only five records that will write all records, but when I used a csv file only the last record is written. I did read a post which said that this could be related to using a scalar variable in the stored proc but I don't think that this is right because when I use the text file it's still the same stored proc. Please advise.
Thanks!
here's the stored proc:
USE [SomeDB]
GO
/****** Object: StoredProcedure [dbo].[SaveUser] Script Date: 8/1/2016 9:25:24 AM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
Alter PROCEDURE [dbo].[SaveUser]
-- Add the parameters for the stored procedure here
#PartnerID INT,
#SourceID INT,
#OrgSourcedIDs NVARCHAR(50),
#Role NVARCHAR(50),
#UserID NVARCHAR(50),
#GivenName NVARCHAR(50),
#FamilyName NVARCHAR(50),
#Email NVARCHAR(50),
#Grade NVARCHAR(50),
#Identifier NVARCHAR(50)
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE #ReturnVal NVARCHAR(10)
DECLARE #IsTransfer Bit = 0
DECLARE #IsUpdate BIT = 0
SELECT #IsTransfer = CASE WHEN OrgSourcedIDs != #OrgSourcedIDs THEN 1 ELSE 0 END,
#IsUpdate = CASE WHEN HASHBYTES('SHA', GivenName +FamilyName +Email +Grade ) != HASHBYTES('SHA', #GivenName + #FamilyName + #Email + #Grade ) THEN 1 ELSE 0 END
FROM dbo.tblUsers a
WHERE a.PartnerID = #PartnerID AND a.SourcedID = #SourceID
IF ##RowCount = 0
BEGIN
-- If not, add it to staging table with ACTION = INSERT (into tblUser)
INSERT INTO dbo.tblUsers
( PartnerID, SourcedID, OrgSourcedIDs, Role, UserID,
GivenName, FamilyName, Email, Grade, Identifier,
Action )
VALUES
( #PartnerID, #SourceID, #OrgSourcedIDs, #Role, #UserID,
#GivenName, #FamilyName, #Email, #Grade, #Identifier,
'Create' )
--SELECT #ReturnVal = 'INSERT'
END
ELSE IF (#IsTransfer = 1)
BEGIN
UPDATE dbo.tblUsers
SET
OrgSourcedIDs = #OrgSourcedIDs,
UserID = #UserID,
GivenName = #GivenName,
FamilyName = #FamilyName,
Email = #Email,
Grade = #Grade,
Identifier = #Identifier,
Action = 'Transfer'
WHERE
PartnerID = #PartnerID
AND SourcedID = #SourceID
END
ELSE IF(#IsUpdate = 1)
BEGIN
UPDATE dbo.tblUsers
SET
UserID = #UserID,
GivenName = #GivenName,
FamilyName = #FamilyName,
Email = #Email,
Grade = #Grade,
Identifier = #Identifier,
Action = 'Update'
WHERE
PartnerID = #PartnerID
AND SourcedID = #SourceID
END
--SELECT #ReturnVal
END
GO
I am attempting to paste information from a spreadsheet to a form in my Access database but I get an error at the Do Until IsEmpty(wks.Cells(i, 1)) line. I am using Access 2010.
Option Compare Database
Private Sub Cmd_Mass_Upload_Click()
If MsgBox("ARE YOU SURE YOU WANT TO UPDATE RECORDS?", vbOKCancel, "CONFIRM MASS UPDATE") = vbOK Then
Dim wks
Dim db As Database
Dim rsCheckDuplicate As Recordset
Dim rsUpdateCC As Recordset
Dim strSQLCheckDuplicate As String
Dim strUpdateCC As String
Dim succesfullyUpdated As Integer
succesfullyUpdated = 0
i = 1
'If Me.Ctl2003 = True Then
Set wks = Me.upLoadSpreadsheet2010
'End If
'If Me.Ctl2010 = True Then
' Set wks = Me.upLoadSpreadsheet2010
'End If
Do Until IsEmpty(wks.Cells(i, 1))
i = i + 1
Loop
Set db = CurrentDb
If i > 1 Then
For j = 1 To i - 1
strSQLCheckDuplicate = "SELECT TBL_OPEN_VOUCHERS.[VOUCHER NUMBER], TBL_OPEN_VOUCHERS.[INVOICE NUMBER] " & _
"FROM TBL_OPEN_VOUCHERS " & _
"WHERE (((TBL_OPEN_VOUCHERS.[VOUCHER NUMBER])='" & wks.Cells(j, 1) & "') AND ((TBL_OPEN_VOUCHERS.[INVOICE NUMBER])='" & wks.Cells(j, 2) & "'));"
'"WHERE (((TBL_OPEN_VOUCHERS.[VOUCHER NUMBER])='" & wks.Cells(j, 1) & "'));"
Set rsCheckDuplicate = db.OpenRecordset(strSQLCheckDuplicate)
If rsCheckDuplicate.EOF Then
MsgBox "Voucher number " & wks.Cells(j, 1) & " not available in local system!"
Else
rsCheckDuplicate.MoveLast
rsCheckDuplicate.MoveFirst
If rsCheckDuplicate.RecordCount > 1 Then
MsgBox "Voucher number " & wks.Cells(j, 1) & " has multiple entries in local system! Please update manually!"
End If
If Len(wks.Cells(j, 3)) = 6 Then
strUpdateCC = "UPDATE TBL_OPEN_VOUCHERS SET TBL_OPEN_VOUCHERS.[CHARGE TO] = '" & wks.Cells(j, 3) & "', TBL_OPEN_VOUCHERS.COMMENTS_NOTES = '" & Form_FRM_MAIN.USER.Caption & ": PART OF MASS UPLOAD ON " & Now() & "' " & _
"WHERE (((TBL_OPEN_VOUCHERS.[VOUCHER NUMBER])='" & wks.Cells(j, 1) & "') AND ((TBL_OPEN_VOUCHERS.[INVOICE NUMBER])='" & wks.Cells(j, 2) & "'));"
'"WHERE (((TBL_OPEN_VOUCHERS.[VOUCHER NUMBER])='" & wks.Cells(j, 1) & "'));"
DoCmd.RunSQL strUpdateCC
succesfullyUpdated = succesfullyUpdated + 1
Else
MsgBox "Please check Cost Center"
End If
End If
Next
End If
Set wks = Nothing
MsgBox "Successfully uploaded " & succesfullyUpdated & " of " & i - 1 & " records!"
End If
End Sub
Private Sub Command7_Click()
On Error GoTo Err_Command7_Click
DoCmd.Close
Exit_Command7_Click:
Exit Sub
Err_Command7_Click:
MsgBox Err.Description
Resume Exit_Command7_Click
End Sub
Private Sub Ctl2003_Click()
If Me.Ctl2003 = False Then Me.Ctl2010 = True
If Me.Ctl2003 = True Then Me.Ctl2010 = False
End Sub
Private Sub Ctl2010_Click()
If Me.Ctl2010 = True Then Me.Ctl2003 = False
If Me.Ctl2010 = False Then Me.Ctl2003 = True
End Sub
What was the actual error message you were getting?
Have you tried creating a connection to the spreadsheet as a linked table, then treating the spreadsheet as a table?
Your code doesn't specify the datatype of the "wks" object, so the code doesn't know it is a spreadsheet.
Here's the approach I'd use:
Link the spreadsheet as a linked table (External Data, Import Excel Spreadsheet, Link to the DataSource.) This will create a "table" in access which is linked to a spreadsheet that is in a nominated location.
Use a query to identify records that are in your linked table but not in your local table (select s.* from upLoadSpreadsheet2010 s left outer join tbl_open_vouchers v on s.somekeycolumnidontknowthenameof = v.[voucher number] and s.someotherkeycolumn = v.[Invoice Number] where v.[voucher number] is null)
Open the query in your code, iterate through it, and do you thing, or better still create an Append query to do the job for you without any code at all.
The only challenge then is ensure the excel spreadsheet is in the right place at the right time. New spreadsheet? Just put it in the same place as the last spreadsheet and run the process again.
I created a variable className and I assigned values to it.
I have another procedure in oracle that sends emails to me.
How do I pass this value into header and body of my email?
VARIABLE className varchar2(30)
:classname := 0;
BEGIN
FOR i IN
(
SELECT CLASS_INSTANCE_COUNT , CLASS_NAME
FROM MODEL_CLASS_COUNTS
WHERE TRUNC(COUNT_DATETIME) = TRUNC(SYSDATE)
)
LOOP
IF i.CLASS_INSTANCE_COUNT = 0
THEN
:className := i.CLASS_NAME;
EMAIL('myemail#col.com', 'email header: &className is 0', 'body: count for &className is 0');
END IF;
END LOOP;
END;
/
My guess is that you don't want to have either a SQL*Plus variable or a substitution variable. I'm guessing that you just want
BEGIN
FOR i IN
(
SELECT CLASS_INSTANCE_COUNT , CLASS_NAME
FROM MODEL_CLASS_COUNTS
WHERE TRUNC(COUNT_DATETIME) = TRUNC(SYSDATE)
)
LOOP
IF i.CLASS_INSTANCE_COUNT = 0
THEN
EMAIL('myemail#col.com',
'email header: ' || i.class_name || ' is 0',
'body: count for ' || i.class_name || ' is 0');
END IF;
END LOOP;
END;
I'm trying to have greentext support for my Rails imageboard (though it should be mentioned that this is strictly a Ruby problem, not a Rails problem)
basically, what my code does is:
1. chop up a post, line by line
2. look at the first character of each line. if it's a ">", start the greentexting
3. at the end of the line, close the greentexting
4. piece the lines back together
My code looks like this:
def filter_comment(c) #use for both OP's and comments
c1 = c.content
str1 = '<p class = "unkfunc">' #open greentext
str2 = '</p>' #close greentext
if c1 != nil
arr_lines = c1.split('\n') #split the text into lines
arr_lines.each do |a|
if a[0] == ">"
a.insert(0, str1) #add the greentext tag
a << str2 #close the greentext tag
end
end
c1 = ""
arr_lines.each do |a|
strtmp = '\n'
if arr_lines.index(a) == (arr_lines.size - 1) #recombine the lines into text
strtmp = ""
end
c1 += a + strtmp
end
c2 = c1.gsub("\n", '<br/>').html_safe
end
But for some reason, it isn't working! I'm having weird things where greentexting only works on the first line, and if you have greentext on the first line, normal text doesn't work on the second line!
Side note, may be your problem, without getting too in depth...
Try joining your array back together with join()
c1 = arr_lines.join('\n')
I think the problem lies with the spliting the lines in array.
names = "Alice \n Bob \n Eve"
names_a = names.split('\n')
=> ["Alice \n Bob \n Eve"]
Note the the string was not splited when \n was encountered.
Now lets try this
names = "Alice \n Bob \n Eve"
names_a = names.split(/\n/)
=> ["Alice ", " Bob ", " Eve"]
or This "\n" in double quotes. (thanks to Eric's Comment)
names = "Alice \n Bob \n Eve"
names_a = names.split("\n")
=> ["Alice ", " Bob ", " Eve"]
This got split in array. now you can check and append the data you want
May be this is what you want.
def filter_comment(c) #use for both OP's and comments
c1 = c.content
str1 = '<p class = "unkfunc">' #open greentext
str2 = '</p>' #close greentext
if c1 != nil
arr_lines = c1.split(/\n/) #split the text into lines
arr_lines.each do |a|
if a[0] == ">"
a.insert(0, str1) #add the greentext tag
# Use a.insert id you want the existing ">" appended to it <p class = "unkfunc">>
# Or else just assign a[0] = str1
a << str2 #close the greentext tag
end
end
c1 = arr_lines.join('<br/>')
c2 = c1.html_safe
end
Hope this helps..!!
I'm suspecting that your problem is with your CSS (or maybe HTML), not the Ruby. Did the resulting HTML look correct to you?