Here is my code:
while true do
opr = io.read() txt = io.read()
if opr == "print" then
print(txt)
else
print("wat")
end
end
What I'm trying to do is make it where you type print and then whatever you want like this:
print text
And it'll print text but I can't seem to do it on the same line without having to press enter after typing print. I always end up having to write it like:
print
text
If anyone knows how I can fix this please answer.
When called without arguments, io.read() reads a whole line. You could read the line and get the words using pattern matching:
input = io.read()
opr, txt = input:match("(%S+)%s+(%S+)")
The above code assumes that there is just one word for opr and one word for txt. If there might be zero or more txt, try this:
while true do
local input = io.read()
local i, j = input:find("%S+")
local opr = input:sub(i, j)
local others = input:sub(j + 1)
local t = {}
for s in others:gmatch("%S+") do
table.insert(t, s)
end
if opr == "print" then
print(table.unpack(t))
else
print("wat")
end
end
Well, that is because io.read() nactually reads an entire line.
What you have to do is read a line:
command = op.read()
and then analyze the string.
For what you want to do, the best is probably to iterate the string looking for spaces to separate each word and save it into a table. Then you can pretty much do with it whatever you want.
You can also interpret the command on the fly while iterating:
Read in the first word;
if it is "print" then read in the rest of the line and print it;
if it is "foo" read in the next 3 words as aprameters and call bar();
etc.
For now I am leaving the implementation for to you. If you need help with that leave a comment.
Related
With the help of Userforms and textboxes, i can add new personnel to my personnel file, but there is something wrong in my code and the code does not work. I do get an error while carrying it out. The error says "Compile error: Method or data member not found". I dont know what is wrong with my code, my expectations are that i fill in some Textboxes and i want them added to the already existing seq file (Notepad). But it doesnt let me do that and i dont know why.
I would be happy if someone can find the problem and give a solution.
Thanks in advance.
If you need code from other Commandbuttons,Userforms,etc.. Please tell me.. I dont know entirely what to publish now.
I have already tried changing the Userform_Nieuw names, but to no avail.
Private Sub seq_bestand_maak_databank()
Dim diploma As String
Dim pad As String
pad = "C:\Users\fhaka\Downloads\Overzicht_Personeelsleden.txt"
If UserForm_Nieuw.OptionButton1.Value = True Then
diploma = "Secundair"
ElseIf UserForm_Nieuw.OptionButton2.Value = True Then
diploma = "Bachelor"
ElseIf UserForm_Nieuw.OptionButton3.Value = True Then
diploma = "Master"
End If
If CInt(nieuw.Label1.Caption) = 1 Then
Open pad For Output As #1
Else
Open pad For Append As #1
End If
Write #1, CInt(UserForm_Nieuw.Label1.Caption), UserForm_Nieuw.Voornaam, UserForm_Nieuw.Naam, CInt(UserForm_Nieuw.Aantal_kinderen), UserForm_Nieuw.Geboortedatum, UserForm_Nieuw.Startdatum, "---N/A---", diploma, "0", "---N/A---", "---N/A---", "EOR"
Close #1
End Sub
The goal is that the commandbutton works again and that i can add more personnel now.
The #1 part in Open pad For Output As #1 etc is a file handle. To obtain a file handle, you need to call FreeFile. You cannot just assume that file handle #1 is available at all times.
Try this:
Dim iOutputFile As Integer
iOutputFile = FreeFile
If CInt(nieuw.Label1.Caption) = 1 Then
Open pad For Output As #iOutputFile
Else
Open pad For Append As #iOutputFile
End If
Write #iOutputFile, CInt(UserForm_Nieuw.Label1.Caption), UserForm_Nieuw.Voornaam, UserForm_Nieuw.Naam, CInt(UserForm_Nieuw.Aantal_kinderen), UserForm_Nieuw.Geboortedatum, UserForm_Nieuw.Startdatum, "---N/A---", diploma, "0", "---N/A---", "---N/A---", "EOR"
Close #iOutputFile
It looks like you have not defined the method of the userform. You failed to compile and the highlight is on the UserForm_Nieuw.Voornaam. So I take that is some sort of input field for the first name? Check whether it is really called that or if it does no have the old default name (something like "Textbox275" or some such like your other elements, e.g. OptionButton1 and 2).
My question is how to read beginning from the end of a text file.
For example,
do
read(1,*) i
print *,i
end do
will read each line in the file 1, and print the contents to the terminal. How would I do this starting from the end of the file?
You can achieve what you want by using inquire, access=stream, and the pos tag in the read statement. A quick 10 minute exercise gives the following.
program foo
implicit none
integer fd, i, j, m, n
character, allocatable :: s(:)
character :: c
open(newunit=fd,file='foo.f90',access='stream',status='old', &
position='append')
inquire(fd, pos=n)
allocate(s(n))
m = 1
do i = n-1, 1, -1
read(fd, pos=i) c
s(m:m) = c
if (iachar(c) == 10) then
do j = m, 1, -1
write(*,'(A1)',advance='no') s(j)
end do
m = 1
else
m = m + 1
end if
end do
write(*,*)
do j = m-1, 1, -1
write(*,'(A1)',advance='no') s(j)
end do
write(*,*)
close(fd)
end program foo
Save this into a file named foo.f90, compile, and run. Someone here can make it more elegant. Edited original version: don't need to use array sections for s(j).
It is not possible. Reading always starts from a certain point, and proceeds forward. By default it starts from the first byte; but you can jump to some other location.
The critical issue is, in a free-format file, there is no way to know where the lines start unless you read the file. You could jump to the last byte, check whether it is a line separator or not, then jump to the byte before it if it wasn't, crawling back till you find a newline, but it would be very inefficient.
A better way would be to read the whole file once, remembering where the newlines were; then iterate this array backwards, jumping to each line's start position to read it. This is not as inefficient, but it is not great, either.
The best way, if you have the memory for it, is to read in the whole file into an array of lines, then reverse the array in-memory.
Hi I am trying to search for a line which contains whats the user inputs in a text box and display the whole line. My code below doesnt display a messsagebox after the button has been clicked and i am not sure if the record has been found
Dim filename, sr As String
filename = My.Application.Info.DirectoryPath + "\" + "mul.txt"
Dim file As String()
Dim i As Integer = 0
file = IO.File.ReadAllLines(filename)
Dim found As Boolean
Dim linecontain As Char
sr = txtsr.ToString
For Each line As String In file
If line.Contains(sr) Then
found = True
Exit For
End If
i += 1
If found = True Then
MsgBox(line(i))
End If
Next
End Sub
You should be calling ReadLines here rather than ReadAllLines. The difference is that ReadAllLines reads the entire file contents into an array first, before you can start processing any of it, while ReadLines doesn't read a line until you have processed the previous one. ReadAllLines is good if you want random access to the whole file or you want to process the data multiple times. ReadLines is good if you want to stop processing data when a line satisfies some criterion. If you're looking for a line that contains some text and you have a file with one million lines where the first line matches, ReadAllLines would read all one millions lines whereas ReadLines would only read the first.
So, here's how you display the first line that contains specific text:
For Each line In File.ReadLines(filePath)
If line.Contains(substring) Then
MessageBox.Show(line)
Exit For
End If
Next
With regards to your original code, your use of i makes no sense. You seem to be using i as a line counter but there's no point because you're using a For Each loop so line contains the line. If you already have the line, why would you need to get the line by index? Also, when you try to display the message, you are using i to index line, which means that you're going to get a single character from the line rather than a single line from the array. If the index of the line is greater than the number of characters in the line then that is going to throw an IndexOutOfRangeException, which I'm guessing is what's happening to you.
This is what comes from writing code without knowing what it actually has to do first. If you had written out an algorithm before writing the code, it would have been obvious that the code didn't implement the algorithm. If you have no algorithm though, you have nothing to compare your code to to make sure that it makes sense.
First of all I have little to no knowledge about VBA.. probably none at all. However I was asked to create a VBA program that paste text from clipboard in different cells. My text has the following format:
seminar: name of Seminar (in cell(1,1))
first name: participant's first name (in cell(1,2))
last name: participant's last name (in cell(1,3)) etc..
So far I was able to read the text from clipboard. Then I found the position of the ":" in order to paste only what is AFTER it in the cell.
At this point I thought to find the position of the RETURN character in order to know where the first line ends(ex. "name of Seminar") with this line of code which I found online:
end_str = InStr(str, vbCrLf) - 1
and with the Right (string, length) function to get the relative text.
This is not working. I think because there are not return character in the string variable that holds the data? I don't know.
My question is: Is it possible to check the RETURN character somehow or Is there a better way to create this program?
Thank you in advance.
An easy way would be to use the split function to get each line separately:
Suppose you have a function called ClipBoard_GetData that returns the text from ClipBoard, you could use something like this:
Dim lines() As String
lines = Split(ClipBoard_GetData, vbNewLine)
For Each Line In lines
' Parse each line to get whatever parts you want
Next
This should work fine.. and if you don't -already have a function that gets what's in the clipboard, you could refer to this link
Hope that helps :)
Most likely the Ascii code you're after is 10 (ie newline). So you could find the position of the newline like so:
i = Instr(str, Chr(10))
However, are you aware that you don't need to parse that clipboard text at all. You can write arrays directly into worksheet cells. So all you'd need to do is use the Split function. The procedure below will complete everything you need:
Public Sub PasteText(str As String)
Dim arr() As String
Dim cols As Integer
arr = Split(str, Chr(10))
cols = UBound(arr) + 1
Sheet1.Range("A1").Resize(, cols).Value = arr
End Sub
I need some direction on how to solve a problem I am working on. The root issue is that I need to work with CSV files in another program. The source system that creates the CSV files does not strip out CRLF in any of the data fields that get exported (meaning some fields have an embedded CRLF). As a result I receive a CSV file that has malformed rows in it. My end goal is an utility that will
check the first column of each row (which if correct is a GUID with a length of 36, or
count the columns in each row (which is the example below).
In the example below I am looking at the column count. If the correct count is 18 then I want it to write that row to a new file. If the column count is not correct I want to remove the CRLF from that row until the column count is correct.
Again, two ways to solve the issue that I know of:
Check the length of the first column for a length of 36 (before the first comma and excluding the first row which is the title row), or
count the columns and remove any trailing CRLF until the column count is equal to 18 (the total column count).
My issue with the code so far is being able to write out a valid row to a new file. Currently it writes out System.String[] instead of the actual row.
Public Class Form1
Private Sub btnFixit_Click(sender As Object, e As EventArgs) Handles btnFixit.Click
Dim iBadRowNumber As Integer = vbNull
Dim strFixedFile As System.IO.StreamWriter = My.Computer.FileSystem.OpenTextFileWriter(Me.txtFixedFile.Text, True)
Using MyReader As New Microsoft.VisualBasic.FileIO.TextFieldParser(Me.txtBaselineFileToProcess.Text)
MyReader.TextFieldType = FileIO.FieldType.Delimited
MyReader.SetDelimiters(",")
Dim currentRow As String()
While Not MyReader.EndOfData
Try
currentRow = MyReader.ReadFields()
If currentRow.Count = 18 Then
strFixedFile.WriteLine(currentRow)
Else
' Future code here to fix the line
End If
Catch ex As Microsoft.VisualBasic.FileIO.MalformedLineException
MsgBox("Line " & ex.Message &
"is not valid and will be skipped.")
End Try
End While
End Using
strFixedFile.Close()
End Sub
End Class
Here is an example of 2 correct rows with one incorrect row in the middle. In this example the row beginning with Sometown is really part of the prior row. I have also seen that one true row may be broken into three or more partial rows like similar to what you see in the Sometown row.
CustomerId,CustomerName,Status,Type,CustomerNumber,DBA,Address1,Address2,City,State,ZipCode,WebAddr,EMail,SalesCode,ServiceCode,DivisionCode,BranchCode,DepartmentCode
6d0125cd-70cf-4048-9ee1-8d9682e426a5,"Smith,James",Active,Customer,8,,103 Long Dr,,AnotherTown,NJ,000000,,,!!S,!%9,!!#,!!#,"!""."
35ed375c-c226-4879-a789-469cae63383c,"Doe, John",Active,Customer,55281,,28 Short Drive,,
Sometown,CA,12345,,
email#domain.com,"!$,",!$^,!!#,!!#,!!K
a5972bce-408f-4def-b77c-4ae0148dd045,"Duck,Donald",Active,Customer,25,,236 North Main St,,Mytown,PA,11111,,,!!2,!%9,!!#,!!#,"!""."
There may be much more elegant ways to perform the specific task. I am open either to corrections to my logic above or a totally different way to solve the problem either in VB.net or PowerShell.
Normally, csv can have multiline fields without a problem. But those need to be surrounded with quotes.
In your example this doesn't seem the case, but on the other hand there is no multiline field either, the field with value Sometown starts at a new line. So I wonder if this is the original data.
In case your multiline fields are surrounded with quotes you need to inform your parser about it.
But even with the single lines you will have problems caused by the fields with a seperator inside. Luckily those are quoted (as they should be), so you need to set the TextFieldParser.HasFieldsEnclosedInQuotes property as wel.
Now, if your multiline fields happen to be quoted (as they should be), the above setting should solve everything.
Update
You could do something like this:
currentRow = MyReader.ReadFields()
If currentRow.Count = 18 Then
strFixedFile.WriteLine(currentRow)
Else
'Write current row without newline
'Read next line/row
'WriteLine this row
End If
But you'll have to take care of fields like "Smith,James" with a seperator inside. Make sure your parser handles quoted fields properly (see above).
The most straightforward approach would probably be a variation of your first validation check:
Read the file line-by-line and keep both the current and the previous line in a buffer.
Check if the beginning of the line is a proper GUID (e.g. with a regular expression).
If the current line does not start with a GUID, append it to the previous line.
Otherwise write the previous line to the output file unless it's empty, then replace it with the current line.
I don't know VB.net, but in PowerShell it would look somewhat like this:
$reader = New-Object IO.StreamReader ('C:\path\to\input.csv')
$writer = New-Object IO.StreamWriter ('C:\path\to\output.csv', $false)
$writer.WriteLine($reader.ReadLine()) # copy CSV header
$output = '' # output buffer
$current = '' # pre-buffered current line from input file
while ($reader.Peek() -ge 0) {
# read line into pre-buffer
$current = $reader.ReadLine()
$hasGUID = $current -match '^[a-f0-9]{8}(-[a-f0-9]{4}){3}-[a-f0-9]{12},'
# append line to output buffer if it doesn't have a GUID, otherwise
# write the output buffer to file if it contains data and move the
# current line to the output buffer
if (-not $hasGUID) {
$output += $current
} else {
if ($output) { $writer.WriteLine($output) }
$output = $current
}
}
# write remaining pre-buffered line (if there is one)
if ($current -and $hasGUID) { $writer.WriteLine($current) }
$reader.Close(); $reader.Dispose()
$writer.Close(); $writer.Dispose()