Splitting string quotation mark errors - vb.net

tl:dr
How can I programatically flag a quotation mark (") when it is not a quote-comma (",) or a comma-quote (,")?
I am running a program that opens csv files, reads each line, then splits the line based on the location of the commas. There are enough text strings that have quotes in them, so I am using
filereader1.HasFieldsEnclosedInQuotes = True
However, when the files were created, there was no regard for having even numbers of quotes in the lines. Most of the time, it's not a big deal. There are only a couple of instances per folder of files.
But, I'm running into a few where it's a huge number. Dozens of instances in a file of several thousand lines. There isn't a simple way to manually error-check these.
So, I'm trying to do a verify that a string has rogue quotes. A comma-quote (,") or quote-comma ("), would be okay, but a quote (") just floating around would pull up an input box displaying the text line for manual fixes.
I can't use an odd number of quotes, because I've found even numbers of error quotes.
Below is the code as it stands.
Using filereader1 As New Microsoft.VisualBasic.FileIO.TextFieldParser(files_(i))
filereader1.TextFieldType = FieldType.Delimited
filereader1.Delimiters = New String() {","}
filereader1.HasFieldsEnclosedInQuotes = True
While Not filereader1.EndOfData
'While (filereader1.EndOfData = False) ' looks for the end of the file and resets stuff
split_string = filereader1.ReadFields()
This is something of what I am thinking.
I would like to run a readline instead of a readfield, and I would assign that to a variable. If the readline had a quote, but that could not be a quote-comma OR a comma-quote, the variable would get displayed in an input box for manual updating. Then the fixed variable would get parsed into the split_string array.
If the quotes all fit the rule above, the string would get parsed normally.

Could you do a count of the different type of strings in the readLine, and if the count of all quotes versus the sum of all ", and ," don't match, then you have an issue?
Public Function CountChar(originalString As String, findString As String) as Long
Dim lLen As Long = 0
Dim lCharLen As Long = 0
Dim lAns As Long = 0
Dim sChar As String = ""
Dim lCtr As Long = 0
Dim lEndOfLoop As Long = 0
lLen = Len(originalString)
lCharLen = Len(findString)
lEndOfLoop = (lLen - lCharLen) + 1
For lCtr = 1 To lEndOfLoop
sChar = Mid(originalString, lCtr, lCharLen)
If StrComp(sChar, findString, vbTextCompare) = 0 Then lAns = lAns + 1
Next
return lAns
End Function
Usage
'if the count of all quotes does not equal count of ", + ,", then there is an issue.
if CountChar(thisLine, chr(34)) <> (countChar(thisLine, chr(34) & ",") + countChar(thisLine, & "," & chr(34)) then
'rogue quotes
end if

So, this is what I ended up doing.
I read each line from the csv file.
I check to see how many quotes are in the line.
If the number is zero, I parse based on commas alone.
If there are an odd number of quotes, I eliminate ALL the quotes in the line, and send it to the manual error-checking.
If there are an even number of quotes, I replace the character string ," and ", with ::
Then I parse the line on both commas and ::
This seems to be working.
Using filereader As New Microsoft.VisualBasic.FileIO.TextFieldParser(files_(i), System.Text.Encoding.Default) 'system text decoding adds odd characters
While Not filereader.EndOfData
filereader.TextFieldType = FieldType.Delimited
'filereader.Delimiters = New String() {","}
filereader.SetDelimiters(",") 'tried new from Don's program 6/12
filereader.HasFieldsEnclosedInQuotes = True
filereader.TextFieldType = FieldType.Delimited
Try
'split_string = filereader1.ReadFields()
whole_string = filereader.ReadLine()
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MessageBox.Show(ex.Message & " : " & FileName & " ; " & filereader.ErrorLine)
error_throw = filereader.ErrorLine
error_throw = error_throw.Replace("""", " ")
split_string = Split(error_throw, ",")
'MsgBox("In catch routine, split string (0) " & split_string(0))
End Try
Dim cnt As Integer = 0
Dim MyRegex As New Regex("""[^""]*""|(,)")
For Each c As Char In whole_string
If c = """" Then cnt = cnt + 1
Next
'MsgBox("cnt = " & cnt)
If cnt = 0 Then 'no quotes
split_string = Split(whole_string, ",") 'split by commas
'MsgBox("no quotes")
ElseIf cnt Mod 2 = 0 Then 'even number of quotes
Dim pattern1 As String = "\.?(,"")+"
Dim pattern2 As String = "\.?("",)+"
Dim rgex1 As New Regex(pattern1)
Dim rgex2 As New Regex(pattern2)
Dim replace1 As String = "::"
Dim replace2 As String = "::"
Dim whole_string1 As String = rgex1.Replace(whole_string, replace1)
Dim whole_string2 As String = rgex2.Replace(whole_string1, replace2)
whole_string1 = rgex1.Replace(whole_string, replace1)
whole_string2 = rgex2.Replace(whole_string1, replace2)
'MsgBox(whole_string & " >> " & whole_string1 & " >> " & whole_string2)
'split_string = Split(whole_string2, ",") 'non-regex code that allows program to run
split_string = Regex.Split(whole_string2, ",|([<::>+].*[<::>+])")
'(",(?=(?:[^\""]*\""[^\""]*\"")*(?![^\""]*\""))")
'MsgBox("Before " & split_string(0) & " | " & split_string(1) & " | " & split_string(2) & " | " & split_string(3) & " | " & split_string(4) & " | " & split_string(5) & " | " & split_string(6) & " | " & split_string(7))
Dim arraycount_2 As Integer = split_string.getupperbound(0)
For p = 0 To arraycount_2
split_string(p) = split_string(p).replace("::", "")
Next
'MsgBox("After " & split_string(0) & " | " & split_string(1) & " | " & split_string(2) & " | " & split_string(3) & " | " & split_string(4) & " | " & split_string(5) & " | " & split_string(6) & " | " & split_string(7))
ElseIf cnt Mod 2 <> 0 Then 'odd number of quotes
'MsgBox("Odd quotes")
whole_string = whole_string.Replace("""", " ") 'delete all quotes
split_string = Split(whole_string, ",") 'split by commas
Else
' MsgBox("no answer to ENTRY splitting of Whole_string")
End If

Related

VBA Replace last field in ALL rows within csv around double quotes?

On Error Resume Next
Set FileSysObj = CreateObject("Scripting.FileSystemObject")
Const ForReading = 1 ' Declare constant for reading for more clarity
Dim cntFile, strCSVFullFile, strCSVFile, strDIR, cntBadLines, cntAllLines, strArchiveDir, strSafeTime,strSafeDate
' -------------------------------------------------------------------------------------------
' Specify CSV file name from the input argument
strCSVFile = Wscript.Arguments(1) ' Transactions
strDIR = Wscript.Arguments(2) & "\" ' C:\Temp
strArchiveDir = Wscript.Arguments(3) & "\"
strSafeTime = Right("0" & Hour(Now), 2) & Right("0" & Minute(Now), 2) & Right("0" & Second(Now), 2)
strSafeDate = Year(Date) & Month(Date) & day(Date)
set folder = FileSysObj.getFolder(strDIR)
cntFile = 0
cntBadLines = 0
cntAllLines = 0
for each file in folder.Files
' check if the file is there and echo it.
if InStr(1,file.name,strCSVFile,1) <> 0 then
strCSVFullFile = file.name
cntFile = cntFile + 1
end if
next
if cntFile > 1 or cntFile = 0 then
' error and end
Wscript.Echo "Error - only 1 file required for this process. There are " & cntFile & " file(s) in the directory"
WScript.Quit
end if
wscript.echo "Checking the file " & strCSVFullFile & " in " & strDIR
NoOfCols = Wscript.Arguments(0) ' usually 8
strTemp = "temp.csv"
strmissing = "missingdata.csv"
Set objOutFile = FileSysObj.CreateTextFile(strDIR & strTemp,True)
Set objOutFileM = FileSysObj.CreateTextFile(strDIR & strmissing,True)
Set inputFile = FileSysObj.OpenTextFile(strDIR & strCSVFullFile, ForReading, True)
' Set inputFile as file to be read from
Dim row, column, outline
Dim fields '(7) '8 fields per line
inputFile.ReadAll 'read to end of file
outline = ""
ReDim MyArray(inputFile.Line-2,NoOfCols) 'current line, minus one for header, and minus one for starting at zero
inputFile.close 'close file so that MyArray can be filled with data starting at the top
Set inputFile = FileSysObj.OpenTextFile(strDIR & strCSVFullFile, ForReading, True) 'back at top
strheadLine = inputFile.ReadLine 'skip header , but keep it for the output file
objOutFile.Write(strheadLine & vbCrLf)
anyBadlines = False
badlineflag = False
Do Until inputFile.AtEndOfStream
fullLine = inputFile.Readline
fields = Split(fullLine,",") 'store line in temp array
For column = 0 To NoOfCols-1 'iterate through the fields of the temp array
myArray(row,column) = fields(column) 'store each field in the 2D array with the given coordinates
'Wscript.Echo myArray(row,column)
if myArray(row,0) = " " or myArray(row,1) = " " then
badlineflag = True
'missline = myArray(row,0) & ", " & myArray(row,1) & ", " & myArray(row,2) & ", " & myArray(row,3) & ", " & myArray(row,4) & ", " & myArray(row,5) & ", " & myArray(row,6) & ", " & myArray(row,7)
'Wscript.Echo missline
'Exit For
end if
if column = NoOfCols-1 then
outline = outline & myArray(row,column) & vbCrLf
else
outline = outline & myArray(row,column) & ","
'csvFile = Regex.Replace(csvFile, "(,\s*?"".*?)(,)(\s+.*?""\s*?,)", "$1$3") 'TEST
end if
Next
cntAllLines = cntAllLines + 1
' Wscript.Echo outline
if badlineflag = False then
objOutFile.Write(fullLine & vbCrLf)
else
' write it somewhere else, drop a header in the first time
if anyBadlines = False Then
objOutFileM.Write(strheadLine & vbCrLf)
End if
objOutFileM.Write(outline)
cntBadLines = cntBadLines + 1
badlineflag = False
anyBadlines = True
end if
outline = ""
row = row + 1 'next line
Loop
objOutFile.Close
objOutFileM.Close
inputFile.close
Wscript.Echo "Total lines in the transaction file = " & cntAllLines
Wscript.Echo "Total bad lines in the file = " & cntBadLines
The below line is able to work as it contains 7 commas (8 columns).
URXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,ABC
The below line will throw an error as a result of more commas than 7 in the script.
URXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,Redburn, Europe. Limited
If greater than 7 commas in the CSV file line, the aim is to wrap it all greater than 7 into one field.
E.g. how do you replace Redburn, Europe. Limited string with double quotes as it is one name.
For example, in a text file it would appear like below:
URXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,"Redburn, Europe. Limited"
Is there a way to write a VB or VBA script to do the above and save it as a .csv file (which is opened via notepad to check the double quotes)?
Option Explicit
Option Compare Text
Public Sub ConvertFile()
Dim lngRowNumber As Long
Dim strLineFromFile As String
Dim strSourceFile As String
Dim strDestinationFile As String
strSourceFile = "U:\Book3.csv"
strDestinationFile = "U:\Book4.csv"
Open strSourceFile For Input As #1
Open strDestinationFile For Output As #2
lngRowNumber = 0
Do Until EOF(1)
Line Input #1, strLineFromFile
strLineFromFile = Right(Replace(strLineFromFile, ",", " ", 1), 1000)
Write #2, strLineFromFile
strLineFromFile = vbNullString
Loop
Close #1
Close #2
End Sub
As I see, you use MS Access (due to Option Compare Text line), so there is better built-in instruments for this task.
Use DoCmd.TransferText for it.
1st step is to create output specification via:
Here you can setup delimiters, even that differs from ", and handle other options.
After that you can use your set-up specification via following command
DoCmd.TransferText acExportDelim, "TblCustomers_export_spec", "TblCustomers", "C:\test\1.txt", True
In this case all characters escaping would be done through built-in instruments. It seems to be more easier to correct this code further.
As mentioned, there is VBScript workaround. For given input data, following function will do desired actions for given string:
Option Explicit
Function funAddLastQuotes( _
strInput _
)
Dim arrInput
arrInput = Split(strInput, ",")
Dim intArrSize
intArrSize = UBound(arrInput)
Dim intCurrentElement
Dim strOutput
Dim intPreLastElement
intPreLastElement = 6
For intCurrentElement = 1 To intPreLastElement
strOutput = strOutput & "," & arrInput(intCurrentElement)
Next
Dim strOutputLastField
For intCurrentElement = intPreLastElement + 1 To intArrSize
strOutputLastField = strOutputLastField & "," & arrInput(intCurrentElement)
Next
strOutputLastField = Right(strOutputLastField, Len(strOutputLastField) - 1)
strOutput = Right(strOutput, Len(strOutput) - 1)
strOutput = strOutput & "," & """" & strOutputLastField & """"
funAddLastQuotes = strOutput
End Function
MsgBox funAddLastQuotes("RXW_99,BYQ0JC6,2603834418,2017-10-30,Test,4.962644,2278.0000,Redburn, Europe,,, Limited")
Finally, here is working VBScript solution.
Option Explicit
Const ColumnsBeforeCommadColumn = 6
Function funAddLastQuotes( _
strInput _
)
Dim arrInput
arrInput = Split(strInput, ",")
Dim intArrSize
intArrSize = UBound(arrInput)
Dim intCurrentElement
Dim strOutput
Dim intPreLastElement
intPreLastElement = ColumnsBeforeCommadColumn
For intCurrentElement = 1 To intPreLastElement
strOutput = strOutput & "," & arrInput(intCurrentElement)
Next
Dim strOutputLastField
If (intPreLastElement + 1) < intArrSize _
Then
For intCurrentElement = intPreLastElement + 1 To intArrSize
strOutputLastField = strOutputLastField & "," & arrInput(intCurrentElement)
Next
Else
strOutputLastField = strOutputLastField & "," & arrInput(intArrSize)
End If
strOutputLastField = Right(strOutputLastField, Len(strOutputLastField) - 1)
strOutput = Right(strOutput, Len(strOutput) - 1)
strOutput = strOutput & "," & """" & strOutputLastField & """"
funAddLastQuotes = strOutput
End Function
Public Sub ConvertFile( _
strSourceFile _
)
Dim objFS
Dim strFile
Dim strTemp
Dim ts
Dim objOutFile
Dim objFile
Set objFS = CreateObject("Scripting.FileSystemObject")
Dim strLine
Dim strOutput
Dim strRow
strFile = strSourceFile
strTemp = strSourceFile & ".tmp"
Set objFile = objFS.GetFile(strFile)
Set objOutFile = objFS.CreateTextFile(strTemp,True)
Set ts = objFile.OpenAsTextStream(1,-2)
Do Until ts.AtEndOfStream
strLine = ts.ReadLine
objOutFile.WriteLine funAddLastQuotes(strLine)
Loop
objOutFile.Close
ts.Close
objFS.DeleteFile(strFile)
objFS.MoveFile strTemp,strFile
End Sub
ConvertFile "C:\!accsoft\_in.csv"
You should change following part: ConvertFile "C:\!accsoft\_in.csv as path to your file.
And ColumnsBeforeCommadColumn = 6 is the setting, at which column the chaos with commas begins

Count the number of empty spaces in front and back of the string

I am reading a file line by line in Excel VBA.
I have some strings for example,
" ooo"
" ooo "
I want to find the number of empty spaces in the front of the string. If I use Trim, it is removing empty spaces from both back and front of the string.
You could use the LTrim and RTrim functions. - I would assume that is faster, than looping through the string and doing character comparisons.
Public Function NumberOfLeadingSpaces(ByVal theString As String) As Long
NumberOfLeadingSpaces = Len(theString) - Len(LTrim(theString))
End Function
Public Function NumberOfTrailingSpaces(ByVal theString As String) As Long
NumberOfTrailingSpaces = Len(theString) - Len(RTrim(theString))
End Function
Function test(s As String) As Integer
Dim str As String
str = "[abcdefghijklmnopqrstuvwxyz0123456789]"
Dim spaceCounter As Integer
For i = 1 To Len(s)
If Not Mid(s, i, 1) Like str Then
spaceCounter = spaceCounter + 1
Else
Exit For
End If
Next i
test = spaceCounter
End Function
By popular request: Why use this function instead of Trim, LTrim, etc?
Well, to summarize the full explanation, not all spaces can be removed with Trim. But they will be removed with this function.
Consider this example (I'll borrow PhilS' solution for illustrative purposes):
Sub testSpaceRemoval()
Dim str1 As String
str1 = " " & Chr(32) & Chr(160) & "a"
Debug.Print Chr(34) & str1 & Chr(34)
Debug.Print NumberOfLeadingSpaces(str1)
Debug.Print test(str1)
End Sub
Result:
"  a"
2
3
Here we can see that the string clearly contains 3 spaces, but the solution using LTrim only counted 2.
So, what to use?
Well, it depends. If you have a dataset where you know you won't get non-breaking characters, use Trim as much as you want! If you think you can get non-breaking characters, Trim alone will not be enough.
Characters to look out for are, quoted from the explanation linked above:
leading, trailing, or multiple embedded space characters (Unicode character set values 32 and 160), or non-printing characters (Unicode character set values 0 to 31, 127, 129, 141, 143, 144, and 157)
Trim can remove chr(32) (as demonstrated above) but not chr(160), because 32 is the regular space and 160 is a non-breaking space.
If you're a stickler for covering your behind, consider this total solution:
Function cleanSpecialCharacters(str As String) As String
bannedChars = Chr(127) & "," & Chr(129) & "," & Chr(141) & "," & Chr(143) & "," & Chr(144) & "," & Chr(157) & "," & Chr(160)
str = Application.WorksheetFunction.Clean(str)
str = Application.WorksheetFunction.Trim(str)
For Each c In Split(bannedChars, ",")
str = Replace(str, c, "")
Next
cleanSpecialCharacters = str
End Function
For OP's particular question, it would have to be a little more tailored.
Sub blanks()
cadena = Cells(1, 1)
i = Len(cadena)
Do Until Mid(cadena, i, 1) <> " "
If Mid(cadena, i, 1) = " " Then contador = contador + 1
i = i - 1
Loop
Cells(2, 1) = contador
End Sub
Sub main()
Dim strng As String
Dim i As Long
strng = " ooo "
i = 1
Do While Mid(strng, i, 1) = " "
i = i + 1
Loop
MsgBox "number of front empty spaces: " & i - 1
End Sub
or use LTrim function:
Sub main2()
Dim strng As String
strng = " ooo "
MsgBox "number of front empty spaces: " & Len(strng) - Len(LTrim(strng))
End Sub

Crop last N lines of a string to display in userform textbox

I want to display a textlog string in a userform's textbox.
Code might look like this:
Dim public textlog as string
sub button1_click()
' do some action
textlog = textlog & event_string & vbCrLf
'event_string might exceed more than 2 line
textlog = textlog & "button1 action" & vbCrLf
userform1.textbox1.text = textlog
end sub
sub button2_click()
' do some action
textlog = textlog & event_string & vbCrLf
'event_string might exceed more than 2 line
textlog = textlog & "button2 action" & vbCrLf
userform1.textbox1.text = textlog
end sub
However, the textbox should only contain 20 lines of information, while my
the contents of my textlog will exceed 20 lines.
How can I display only the latest (last) 20 lines of the textlog in textbox1?
You can use this function to return only the last N lines of a string, and then display that in your textbox.
Note that you have to specify what the line break character is. Depending on your specific application, it could be vbCrLf, vbCr, vbLf, or even some other delimiter.
Function GetLastLines(ByVal s As String, ByVal nLinesToDisplay As Long, _
Optional ByVal lineBreakChar As String = vbCrLf)
'Split the string into an array
Dim splitString() As String
splitString = Split(s, lineBreakChar)
'How many lines are there?
Dim nLines As Long
nLines = UBound(splitString) + 1
If nLines <= nLinesToDisplay Then
'No need to remove anything. Get out.
GetLastLines = s
Exit Function
End If
'Collect last N lines in a new array
Dim lastLines() As String
ReDim lastLines(0 To nLinesToDisplay - 1)
Dim i As Long
For i = 0 To UBound(lastLines)
lastLines(i) = splitString(i + nLines - nLinesToDisplay)
Next i
'Join the lines array into a single string
GetLastLines = Join(lastLines, lineBreakChar)
End Function
Example usage:
MsgBox GetLastLines( _
"line 1" & vbCrLf & "line 2" & vbCrLf & "line 3" & vbCrLf _
& "line 4" & vbCrLf & "line 5" & vbCrLf & "line 6", _
4, vbCrLf)
Only the last 4 lines are displayed:
Note that this assumes that your last line is not terminated by a line break. If it is, then you can tweak the code to deal with that.
Alternatively, you can use Excel's built-in SUBSTITUTE function, which is useful in this particular case, because it can locate a specific instance of a given character. So instead of building arrays you can use a one-liner:
Function GetLastLines2(ByVal s As String, ByVal nLinesToDisplay As Long, _
Optional ByVal lineBreakChar As String = vbCrLf)
'An arbitrary character that will never be in your input string:
Dim delim As String: delim = Chr(1)
'How many lines are there?
Dim nLines As Long
nLines = UBound(Split(s, lineBreakChar)) + 1
If nLines <= nLinesToDisplay Then
'No need to remove anything. Get out.
GetLastLines2 = s
Exit Function
End If
'Replace one line break with delim, split the string on it,
'return only second part:
GetLastLines2 = Split( _
WorksheetFunction.Substitute( _
s, lineBreakChar, delim, nLines - nLinesToDisplay), _
delim)(1)
End Function
A = "Cat" & vbcrlf & "Tiger" & vbcrlf & "Lion" & vbcrlf & "Shark hunting florida lynxs" & vbcrlf & "Leopard" & vbcrlf & "Cheetah"
A= StrReverse(A)
NumLines = 3
i=1
For X = 1 to NumLines
i = Instr(i, A, vbcr) + 1
Next
Msgbox StrReverse(Left(A, i - 1))
This is a program that cuts or leaves lines from top or bottom of files.
To use
Cut
filter cut {t|b} {i|x} NumOfLines
Cuts the number of lines from the top or bottom of file.
t - top of the file
b - bottom of the file
i - include n lines
x - exclude n lines
Example
cscript //nologo filter.vbs cut t i 5 < "%systemroot%\win.ini"
The script
Set rs = CreateObject("ADODB.Recordset")
With rs
.Fields.Append "LineNumber", 4
.Fields.Append "Txt", 201, 5000
.Open
LineCount = 0
Do Until Inp.AtEndOfStream
LineCount = LineCount + 1
.AddNew
.Fields("LineNumber").value = LineCount
.Fields("Txt").value = Inp.readline
.UpDate
Loop
.Sort = "LineNumber ASC"
If LCase(Arg(1)) = "t" then
If LCase(Arg(2)) = "i" then
.filter = "LineNumber < " & LCase(Arg(3)) + 1
ElseIf LCase(Arg(2)) = "x" then
.filter = "LineNumber > " & LCase(Arg(3))
End If
ElseIf LCase(Arg(1)) = "b" then
If LCase(Arg(2)) = "i" then
.filter = "LineNumber > " & LineCount - LCase(Arg(3))
ElseIf LCase(Arg(2)) = "x" then
.filter = "LineNumber < " & LineCount - LCase(Arg(3)) + 1
End If
End If
Do While not .EOF
Outp.writeline .Fields("Txt").Value
.MoveNext
Loop
End With

"system resource exceeded" when running a function

I have a field called "sku" which uniquely identifies products on the table, there are about 38k products. I have a "sku generator" which uses other fields in the table to create the SKU. It's worked perfectly without an issue until I started producing SKUs for a large amount of products. I would launch the generator and it would stop around 15,000 and say "System Resource exceeded" and highlight the following code in the function:
Found = IsNull(DLookup("sku", "Loadsheet", "[sku]='" & TempSKU & "'"))
I didn't have time to fully fix the issue, so a temporary fix for me was to split the database in two, and run the sku generator seperately on both files. Now that I have more time I want to investigate why exactly it gets stuck around this number, and if there's a possibility of fixing this issue (it would save some time with splitting files and then grouping them again). I also have an issue with it getting really slow at times, but I think it's because it's processing so much when it runs. Here is the function
Option Compare Database
Private Sub Command2_Click() 'Generate SKU
Command2.Enabled = False: Command3.Enabled = False: Command2.Caption = "Generating ..."
Me.RecordSource = ""
CurrentDb.QueryDefs("ResetSKU").Execute
Me.RecordSource = "loadsheet_4"
Dim rs As Recordset, i As Long
Set rs = Me.Recordset
rs.MoveLast: rs.MoveFirst
For i = 0 To rs.RecordCount - 1
rs.AbsolutePosition = i
rs.Edit
rs.Fields("sku") = SetSKU(rs)
rs.Update
DoEvents
Next
Command2.Enabled = True: Command3.Enabled = True: Command2.Caption = "Generate SKU"
End Sub
Public Function SetSKU(rs As Recordset) As String
Dim TempStr As String, TempSKU As String, id As Integer, Found As Boolean, ColorFound As Variant
id = 1: ColorFound = DLookup("Abbreviated", "ProductColors", "[Color]='" & rs.Fields("single_color_name") & "'")
TempStr = "ORL-" & UCase(Left(rs.Fields("make"), 2)) & "-"
TempStr = TempStr & Get1stLetters(rs.Fields("model"), True) & rs.Fields("year_dash") & "-L-"
TempStr = TempStr & "WR-"
TempStr = TempStr & IIf(IsNull(ColorFound), "?", ColorFound) & "-4215-2-"
TempStr = TempStr & rs.Fields("color_code")
TempSKU = Replace(TempStr, "-L-", "-" & ADDZeros(id, 2) & "-L-")
Found = IsNull(DLookup("sku", "Loadsheet", "[sku]='" & TempSKU & "'"))
While Found = False
id = id + 1
TempSKU = Replace(TempStr, "-L-", "-" & ADDZeros(id, 2) & "-L-")
Found = IsNull(DLookup("sku", "Loadsheet", "[sku]='" & TempSKU & "'"))
Wend
If id > 1 Then
' MsgBox TempSKU
End If
SetSKU = TempSKU
End Function
Public Function Get1stLetters(Mystr As String, Optional twoLetters As Boolean = False) As String
Dim i As Integer
Get1stLetters = ""
For i = 0 To UBound(Split(Mystr, " ")) 'ubound gets the number of the elements
If i = 0 And twoLetters Then
Get1stLetters = Get1stLetters & UCase(Left(Split(Mystr, " ")(i), 2))
GoTo continueFor
End If
Get1stLetters = Get1stLetters & UCase(Left(Split(Mystr, " ")(i), 1))
continueFor:
Next
End Function
Public Function ADDZeros(N As Integer, MAX As Integer) As String
Dim NL As Integer
NL = Len(CStr(N))
If NL < MAX Then
ADDZeros = "0" & N 'StrDup(MAX - NL, "0") & N
Else: ADDZeros = N
End If
End Function
Notes: This function also calls other functions as well that adds a unique identifier to the SKU and also outputs the first letter of each word of the product
Also I'm running on 64 bit access.
If you require any other info let me know, I didn't post the other functions but if needed let me know.
thanks.
I am not 100% sure how you have split the Database into two files and that you are running the generator on both files. However I have a few suggestion to the function you are using.
I would not pass the recordset object to this function. I would rather pass the ID or unique identifier, and generate the recordset in the function. This could be a good start for efficiency.
Next, declare all objects explicitly, to avoid library ambiguity. rs As DAO.Recordset. Try to make use of inbuilt functions, like Nz().
Could Get1stLetters method be replaced with a simple Left() function? How about ADDZeros method?
Using DLookup might be a bit messy, how about a DCount instead? Could the following be any use now?
Public Function SetSKU(unqID As Long) As String
Dim TempStr As String, TempSKU As String
Dim id As Integer
Dim ColorFound As String
Dim rs As DAO.Recordset
id = 1
Set rs = CurrentDB.OpenRecordset("SELECT single_color_name, make, model, year_dash, color_code " & _
"FROM yourTableName WHERE uniqueColumn = " & unqID)
ColorFound = Nz(DLookup("Abbreviated", "ProductColors", "[Color]='" & rs.Fields("single_color_name") & "'"), "?")
TempStr = "ORL-" & UCase(Left(rs.Fields("make"), 2)) & "-"
TempStr = TempStr & Get1stLetters(rs.Fields("model"), True) & rs.Fields("year_dash") & "-L-"
TempStr = TempStr & "WR-"
TempStr = TempStr & ColorFound & "-4215-2-"
TempStr = TempStr & rs.Fields("color_code")
TempSKU = Replace(TempStr, "-L-", "-" & ADDZeros(id, 2) & "-L-")
While DCount("*", "Loadsheet", "[sku]='" & TempSKU & "'") <> 0
id = id + 1
TempSKU = Replace(TempStr, "-L-", "-" & ADDZeros(id, 2) & "-L-")
Wend
If id > 1 Then
'MsgBox TempSKU'
End If
Set rs = Nothing
SetSKU = TempSKU
End Function

Removing duplicated lines from a textbox and getting the count of the removed lines. (VB.NET)

I am developing a bar management software, i did the most of the job but now i don't know the code to remove the same lines from a textbox and getting the number of the removed lines after they are removed.
My code till now:
For Each saveitem As ListViewItem In Form1.ListView1.Items
RichTextBox1.AppendText(saveitem.Text & vbNewLine)
TextBox3.AppendText(saveitem.SubItems(1).Text & vbNewLine)
Next
RichTextBox1.AppendText(vbNewLine & vbNewLine & "TOTALI:" & " " & Form1.TextBoxX5.Text & vbNewLine & "TOTALI pa TVSH:" & " " & TextBox4.Text)
One possible way :
'get array of individual line of text'
Dim textLines = TextBox3.Text.Split(New String(){vbNewLine}, StringSplitOptions.RemoveEmptyEntries)
Dim totalCount = textLines.Length
Dim noDuplicateCount = textLines.Distinct().Count()
'store number of lines removed'
Dim removedLinesCount = totalCount - noDuplicateCount
'join distinct line of texts by new line into single string'
TextBox3.Text = String.Join(vbNewLine, textLines.Distinct())