I've inherited a BASIC script, and I'm trying to rewrite it into Python. I don't know BASIC, or even which version of BASIC this is. Is it Visual Basic? Please help me translate this block of code.
'County Number, District Number, District Name
j = 0
OPEN "" + year.base$ + "dist.csv" FOR INPUT AS #1
INPUT #1, a0$, a1$, a2$, a3$, a4$, a5$, a6$, a7$
DO WHILE NOT EOF(1)
j = j + 1
INPUT #1, a0$, a1$, a2$, a3$, a4$, a5$, a6$, a7$
conumbind(j) = VAL(a0$)
distnumbind(j) = VAL(a1$)
distnameind$(j) = a2$
rate2(j) = VAL(a3$)
rate34(j) = rate2(j) * 2
LOOP
CLOSE #1
iTotal2 = j
Initialize counter.
j = 0
Open file for reading.
OPEN "" + year.base$ + "dist.csv" FOR INPUT AS #1
Read in the first line into 8 variables. These aren't used. I assume they are the header.
INPUT #1, a0$, a1$, a2$, a3$, a4$, a5$, a6$, a7$
Iterate through the rest of the file.
DO WHILE NOT EOF(1)
Increment the counter.
j = j + 1
Read the next line of the file into 8 variables.
INPUT #1, a0$, a1$, a2$, a3$, a4$, a5$, a6$, a7$
Assign the some of the fields to array elements (the VAL function converts to a numeric value).
conumbind(j) = VAL(a0$)
distnumbind(j) = VAL(a1$)
distnameind$(j) = a2$
rate2(j) = VAL(a3$)
rate34(j) = rate2(j) * 2
Finish the loop.
LOOP
Close the input file.
CLOSE #1
Save the record count.
iTotal2 = j
Hello this is QBASIC a DOS based language.
QBasic on Wikipedia
What this code does is to open a text file, in this case a comma separated values files. Each INPUT #1 sentence will fetch one line of the file and assign the values to the string variables (the ones that end in $ character are string variables). Then it will fill some unidimensional arrays with those values.
iTotal2 will be the number of records in the file.
The code does practically nothing, since once the arrays are filled, they are not used.
Related
I'm working on mini program. I have a List of Strings. I'm reading strings from .txt file, and if i have a word that contains 4 and more char then read it. Ok, that's i what is working. Then i need to write all strings (words) in another file, and it's working, but i have problem.
For example i have a word School (6char) and i need trim some char from words. For example
School = chool, hool, etc..
Program = rogram, ogram, gram, etc...
I need to get something like this, here's the code. My code is only working for first char, but not for other in the loop.
For example i will get Program = rogram, but not ogram, gram, etc...
My question is, how to get all trim words from my list of words in input .txt file i have for example:
Program,
school,
etc
and in output .txt file i need to get something like this:
rogram,
ogram,
gram,
chool,
hool,
Here's the code.
Dim path As String = "input_words.txt"
Dim write As String = "trim_words.txt"
Dim lines As New List(Of String)
'reading file'
Using sr As StreamReader = New StreamReader(path)
Do While sr.Peek() >= 4
lines.Add(sr.ReadLine())
Loop
End Using
'writing file'
Using sw As StreamWriter = New StreamWriter(write)
For Each line As String In lines
sw.WriteLine(line.Substring(1, 5))
Next
End Using
The While Loop
A simple way to approach the problem is to use a While loop while the length is bigger than 4
Here while our current string is more than 4 length:
We write it
We remove the first character
For Each line As String In lines
Dim current As String = line
While current.Length > 4
Console.Write(current & ",")
current = current.Remove(0, 1)
End While
Console.Write(current & vbNewLine)
Next
The For Loop
The second way to approach this is using a For loop where the idea is from the length of the current word to (5) applying a last -1 :
We write it
We remove the first character
For Each line As String In lines
Dim current As String = line
For i As Integer = line.Length To 5 Step -1
Console.Write(current & ",")
current = current.Remove(0, 1)
Next
Console.Write(current & vbNewLine)
Next
I made a different solution. Because i needed to limited to 4 char i made this.
Dim path As String = "input_words.txt"
Dim write As String = "trim_words.txt"
Dim lines As New List(Of String)
'reading file'
Using sr As StreamReader = New StreamReader(path)
Do While sr.Peek() >= 4
lines.Add(sr.ReadLine())
Loop
End Using
'writing file'
Using sw As StreamWriter = New StreamWriter(write)
For Each line As String In lines
Dim iStringLength = line.Length
Dim iPossibleStrings = iStringLength - 5
For i = 0 To iPossibleStrings
Console.WriteLine(line.Substring(i, 4))
Next
Next
End Using
Tnx for help #Mederic!
prompt = 'Enter ASCII codes';
dlg_title = 'Input';
num_lines = 5;
defaultans = {''};
answer = inputdlg(prompt,dlg_title,num_lines,defaultans);
answer = answer{1};
m2=matrixA.'; result=char(m2(:)).';
result
What Im trying to do is write a script that when i run it, it will convert the matrix of numbers you input into a sentence. What am I doing wrong?
Your input matrix is a string, not numeric. Change line 7 to:
answer = str2num(answer{1});
But since you never assign anything to matrixA, you might as well change it to this:
matrixA = str2num(answer{1});
I would like to read a data file with a Fortran program, where each line is a list of integers.
Each line has a variable number of integers, separated by a given character (space, comma...).
Sample input:
1,7,3,2
2,8
12,44,13,11
I have a solution to split lines, which I find rather convoluted:
module split
implicit none
contains
function string_to_integers(str, sep) result(a)
integer, allocatable :: a(:)
integer :: i, j, k, n, m, p, r
character(*) :: str
character :: sep, c
character(:), allocatable :: tmp
!First pass: find number of items (m), and maximum length of an item (r)
n = len_trim(str)
m = 1
j = 0
r = 0
do i = 1, n
if(str(i:i) == sep) then
m = m + 1
r = max(r, j)
j = 0
else
j = j + 1
end if
end do
r = max(r, j)
allocate(a(m))
allocate(character(r) :: tmp)
!Second pass: copy each item into temporary string (tmp),
!read an integer from tmp, and write this integer in the output array (a)
tmp(1:r) = " "
j = 0
k = 0
do i = 1, n
c = str(i:i)
if(c == sep) then
k = k + 1
read(tmp, *) p
a(k) = p
tmp(1:r) = " "
j = 0
else
j = j + 1
tmp(j:j) = c
end if
end do
k = k + 1
read(tmp, *) p
a(k) = p
deallocate(tmp)
end function
end module
My question:
Is there a simpler way to do this in Fortran? I mean, reading a list of values where the number of values to read is unknown. The above code looks awkward, and file I/O does not look easy in Fortran.
Also, the main program has to read lines with unknown and unbounded length. I am able to read lines if I assume they are all the same length (see below), but I don't know how to read unbounded lines. I suppose it would need the stream features of Fortran 2003, but I don't know how to write this.
Here is the current program:
program read_data
use split
implicit none
integer :: q
integer, allocatable :: a(:)
character(80) :: line
open(unit=10, file="input.txt", action="read", status="old", form="formatted")
do
read(10, "(A80)", iostat=q) line
if(q /= 0) exit
if(line(1:1) /= "#") then
a = string_to_integers(line, ",")
print *, ubound(a), a
end if
end do
close(10)
end program
A comment about the question: usually I would do this in Python, for example converting a line would be as simple as a = [int(x) for x in line.split(",")], and reading a file is likewise almost a trivial task. And I would do the "real" computing stuff with a Fortran DLL. However, I'd like to improve my Fortran skills on file I/O.
I don't claim it is the shortest possible, but it is much shorter than yours. And once you have it, you can reuse it. I don't completely agree with these claims how Fotran is bad at string processing, I do tokenization, recursive descent parsing and similar stuff just fine in Fortran, although it is easier in some other languages with richer libraries. Sometimes you can use the libraries written in other languages (especially C and C++) in Fortran too.
If you always use the comma you can remove the replacing by comma and thus shorten it even more.
function string_to_integers(str, sep) result(a)
integer, allocatable :: a(:)
character(*) :: str
character :: sep
integer :: i, n_sep
n_sep = 0
do i = 1, len_trim(str)
if (str(i:i)==sep) then
n_sep = n_sep + 1
str(i:i) = ','
end if
end do
allocate(a(n_sep+1))
read(str,*) a
end function
Potential for shortening: view the str as a character array using equivalence or transfer and use count() inside of allocate to get the size of a.
The code assumes that there is just one separator between each number and there is no separator before the first one. If multiple separators are allowed between two numbers, you have to check whether the preceding character is a separator or not
do i = 2, len_trim(str)
if (str(i:i)==sep .and. str(i-1:i-1)/=sep) then
n_sep = n_sep + 1
str(i:i) = ','
end if
end do
My answer is probably too simplistic for your goals but I have spent a lot of time recently reading in strange text files of numbers. My biggest problem is finding where they start (not hard in your case) then my best friend is the list-directed read.
read(unit=10,fmt=*) a
will read in all of the data into vector 'a', done deal. With this method you will not know which line any piece of data came from. If you want to allocate it then you can read the file once and figure out some algorithm to make the array larger than it needs to be, like maybe count the number of lines and you know a max data amount per line (say 21).
status = 0
do while ( status == 0)
line_counter = line_counter + 1
read(unit=10,, iostat=status, fmt=*)
end do
allocate(a(counter*21))
If you want to then eliminate zero values you can remove them or pre-seed the 'a' vector with a negative number if you don't expect any then remove all of those.
Another approach stemming from the other suggestion is to first count the commas then do a read where the loop is controlled by
do j = 1, line_counter ! You determined this on your first read
read(unit=11,fmt=*) a(j,:) ! a is now a 2 dimensional array (line_counter, maxNumberPerLine)
! You have a separate vector numberOfCommas(j) from before
end do
And now you can do whatever you want with these two arrays because you know all the data, which line it came from, and how many data were on each line.
I'm trying to populate an array which is composed of greek letters followed by a subscript "1". I already have the greek letters part:
Dim variables(), variables_o
j = 0
For i = 1 To 25
If i = 13 Or i = 15 Then
Else
j = j + 1
ReDim Preserve variables(j)
variables(j) = ChrW(944 + i)
End If
Next
But I'm having trouble with the subscript part. I figure that if I could use the with ... end with feature then I could do it but I'm having trouble figuring out what objects the with ... end with can take. On this website they say:
With...End With Statement (Visual Basic)
The data type of objectExpression can be any class or structure type or even a Visual Basic elementary type such as Integer.
But I don't know what that means. If could do something like this:
dim one as string
one = "1"
with one
font.subscript = true
end with
Then I could figure out how to do what I want. But the with feature does not seem to act on strings. The problem I'm having is that most of the advice for fonts somewhere along the line use the cell method but I want to populate an array, so I'm having trouble. Again what I would ideally like to do is create some dimension which is simply a subscripted one and then alter my array as follows:
Dim variables(), variables_o
j = 0
For i = 1 To 25
If i = 13 Or i = 15 Then
Else
j = j + 1
ReDim Preserve variables(j)
variables(j) = ChrW(944 + i) & subscript_one
End If
Next
To my knowledge, there are no out-of-the-box methods or properties to store the font.Subscript property of a character or series of characters within a string that also contains the characters.
You could use inline tags, like in HTML, to indicate where the subscript begins and ends. For example:
variables(j) = ChrW(944 + i) & "<sub>1</sub>"
Then, when you write out variable, you would parse the string, remove the tags and set the font.Subscript property accordingly.
However, if you're always appending a '1' to each Greek letter, I would just append it to the string, then set the font.Subscript property on the last character of the string when outputting it. For example:
variables(j) = ChrW(944 + i) & "1"
...
For j = 0 to Ubound(variables)
With Worksheets("Sheet1").Cells(j + 1, 1)
.Value = variables(j)
.Characters(Len(variables(j)), 1).Font.Subscript = True
End With
Next j
If you're writing to something other than a cell in a worksheet, it has to support Rich-Text in order for the subscript to show, e.g. a Rich-Text enabled TextBox on a user form. You should be able to use the .Characters object on those controls in a similar manner.
See MSDN-Characters Object for more information.
I'm writing a piece of code by which I plan to write a .txt file that's a 10x10001 matrix:
do i = 1, 10
read(1,10) seed !Read a number from file 1
write(2,20) seed !Write that number in file 2
do k = 1, 10000
seed = mod((a*seed),m)
R = seed/m
write(2,20) R !I want all these numbers to be next to the seed, not on new lines
end do
end do
But all the R's are written on new lines.
Is there a way to separate every number with a space instead of a new line, or should I implement this same code using C++ and pipelines?
You can make write not add a newline at the end with the following code:
write(2, 20, advance="no") R