I have a sort parm in a JCL that is created using some REXX code as follows:
/* REXX */
'EXECIO * DISKR ZEROGDT (STEM ZGD.'
S21=' '
OUTVAR1=' SORT FIELDS=COPY'
'EXECIO 1 DISKW ACCOUNT (STEM OUTVAR'
DO I=1 TO ZGD.0
ACCTNBR=SUBSTR(ZGD.I,33,16)
IF I=1 THEN DO
OUTVAR1=" OMIT FORMAT=CH,COND=(33,16,EQ,C'"||ACCTNBR||"',OR,"
END
ELSE DO
IF I=ZGD.0 THEN OUTVAR1=S21||" 33,16,EQ,C'"||ACCTNBR||"')"
ELSE OUTVAR1=S21||" 33,16,EQ,C'"||ACCTNBR||"',OR,"
END
'EXECIO 1 DISKW ACCOUNT (STEM OUTVAR'
END
'EXECIO 0 DISKW ACCOUNT (FINIS'
I know that the above REXX code creates a sort parm as follows:
SORT FIELDS=COPY
OMIT FORMAT=CH,COND=(33,16,EQ,C'8257310018808572',OR,
33,16,EQ,C'8257310018076428',OR,
33,16,EQ,C'8257310017959681',OR,
33,16,EQ,C'8257310016504835',OR,
33,16,EQ,C'8257310016059467',OR)
But, it is not able to handle a single record in the input file. I am trying to modify the REXX code to handle a single record but have not been able to. Any help is appreciated.
The code below allows the first line to also be the last, the original code
could not account for this because of the way the IF statements nested.
/* REXX */
'EXECIO * DISKR ZEROGDT (STEM ZGD.'
OUTVAR=' SORT FIELDS=COPY'
'EXECIO 1 DISKW ACCOUNT (STEM OUTVAR'
DO I=1 TO ZGD.0
IF I = 1 THEN
OUTVAR = " OMIT FORMAT=CH,COND=(33,16,EQ,C'" || SUBSTR(ZGD.I,33,16)
ELSE
OUTVAR = COPIES(' ', 21) || " 33,16,EQ,C'" || SUBSTR(ZGD.I,33,16)
IF I = ZGD.0 THEN
OUTVAR = OUTVAR || ")" /* This is the last line, close paren. */
ELSE
OUTVAR = OUTVAR || ",OR," /* Another line to follow, continue */
'EXECIO 1 DISKW ACCOUNT (STEM OUTVAR'
END
'EXECIO 0 DISKW ACCOUNT (FINIS'
For a single line of input this should produce:
SORT FIELDS=COPY
OMIT FORMAT=CH,COND=(33,16,EQ,C'8257310018808572')
For multiple lines it should produce:
SORT FIELDS=COPY
OMIT FORMAT=CH,COND=(33,16,EQ,C'8257310018808572',OR,
33,16,EQ,C'8257310018076428',OR,
33,16,EQ,C'8257310017959681')
Related
I have two .csv files which I am trying to 'multiply' out via a script. The first file is person information and looks basically like this:
First Name, Last Name, Email, Phone
Sally,Davis,sdavis#nobody.com,555-555-5555
Tom,Smith,tsmith#nobody.com,555-555-1212
The second file is account numbers and looks like this:
AccountID
1001
1002
Basically I want to get every name with every account Id. So if I had 10 names in the first file and 10 account IDs in the second file, I should end up with 100 rows in the resulting file and have it look like this:
First Name, Last Name, Email, Phone, AccountID
Sally,Davis,sdavis#nobody.com,555-555-5555, 1001
Tom,Smith,tsmith#nobody.com,555-555-1212, 1001
Sally,Davis,sdavis#nobody.com,555-555-5555, 1002
Tom,Smith,tsmith#nobody.com,555-555-1212, 1002
Any help would be greatly appreciated
You could simply write a for loop for each value to be repeated by it's id count and append the description, but just in the reverse order.
Has that not worked or have you not tried that?
If python works for you, here's a script which does that:
def main():
f1 = open("accounts.txt", "r")
f1_total_lines = sum(1 for line in open('accounts.txt'))
f2_total_lines = sum(1 for line in open('info.txt'))
f1_line_counter = 1;
f2_line_counter = 1;
f3 = open("result.txt", "w")
f3.write('First Name, Last Name, Email, Phone, AccountID\n')
for line_account in f1.readlines():
f2 = open("info.txt", "r")
for line_info in f2.readlines():
parsed_line_account = line_account
parsed_line_info = line_info.rstrip() # we have to trim the newline character from every line from the 'info' file
if f2_line_counter == f2_total_lines: # ...for every but the last line in the file (because it doesn't have a newline character)
parsed_line_info = line_info
f3.write(parsed_line_info + ',' + parsed_line_account)
if f1_line_counter == f1_total_lines:
f3.write('\n')
f2_line_counter = f2_line_counter + 1
f1_line_counter = f1_line_counter + 1
f2_line_counter = 1 # reset the line counter to the first line
f1.close()
f2.close()
f3.close()
if __name__ == '__main__':
main()
And the files I used are as follows:
info.txt:
Sally,Davis,sdavis#nobody.com,555-555-555
Tom,Smith,tsmith#nobody.com,555-555-1212
John,Doe,jdoe#nobody.com,555-555-3333
accounts.txt:
1001
1002
1003
If You Intended to Duplicate Account_ID
If you intended to add each Account_ID to every record in your information file then a short awk solution will do, e.g.
$ awk -F, '
FNR==NR{a[i++]=$0}
FNR!=NR{b[j++]=$0}
END{print a[0] ", " b[0]
for (k=1; k<i; k++)
for (m=1; m<i; m++)
print a[m] ", " b[k]}
' info id
First Name, Last Name, Email, Phone, AccountID
Sally,Davis,sdavis#nobody.com,555-555-5555, 1001
Tom,Smith,tsmith#nobody.com,555-555-1212, 1001
Sally,Davis,sdavis#nobody.com,555-555-5555, 1002
Tom,Smith,tsmith#nobody.com,555-555-1212, 1002
Above the lines in the first file (when the file-record-number equals the record-number, e.g. FNR==NR) are stored in array a, the lines from the second file (when FNR!=NR) are stored in array b and then they combined and output in the END rule in the desired order.
Without Duplicating Account_ID
Since Account_ID is usually a unique bit of information, if you did not intended to duplicate every ID at the end of each record, then there is no need to loop. The paste command does that for you. In your case with your information file as info and you account ID file as id, it is as simple as:
$ paste -d, info id
First Name, Last Name, Email, Phone,AccountID
Sally,Davis,sdavis#nobody.com,555-555-5555,1001
Tom,Smith,tsmith#nobody.com,555-555-1212,1002
(note: the -d, option just sets the delimiter to a comma)
Seems a lot easier that trying to reinvent the wheel.
Can be easily done with arrays
OLD=$IFS; IFS=$'\n'
ar1=( $(cat file1) )
ar2=( $(cat file2) )
IFS=$OLD
ind=${!ar1[#]}
for i in $ind; { echo "${ar1[$i]}, ${ar2[$i]}"; }
I'm trying to display a statement 1000 times in QBASIC (using for statement). I think the program works properly, but I cannot see the 1000 statements because I cannot scroll up and down in the output window of QBASIC. I can see only the last part of the 1000 statements.
FOR x = 1 TO 1000
PRINT "maydie";
PRINT
NEXT x
That will be very hard. For QBasic you have to know how PRINT works. Than with look you could write an TSR program that does what you want in some other language. Alternative is store everything in array and create you own display routine with scrolling. But with 1000 lines will run into memory restrictions
In short, unless you're using a modern take on QBasic, you can't.
What you can do is print the output to a text file:
OPEN "C:\somefile.txt" FOR OUTPUT AS #1
FOR x = 1 TO 1000
PRINT #1, "maydie":
PRINT
NEXT x
This will write "maydie" to C:\somefile.txt 1000 times. Then use some text editor to view the output. You could even use a program to count the lines of text, something like OPEN "C:|somefile.txt" FOR INPUT AS #1: WHILE NOT EOF(1): INPUT #1, junk$: i = i + 1: WEND: PRINT "There were " + STR$(i) + " lines."
Though the other answerers are correct in saying that it is not inbuilt and hence not possible, I agree that this is very desirable! Consequently, I have time and time again devised scripts based on the following:
DIM text(1 to 1000) AS STRING
'Define text below: Here I've just defined it as every line being
'"maydie" with the value of the line number, but it could be whatever.
FOR i = 1 TO 1000
text(i) = STR$(i) + "maydie"
NEXT i
CLS
position% = 0
FOR i = 1 to 25
LOCATE i, 1: PRINT text(i); SPACE$(80 - LEN(text(i)));
NEXT i
DO
x$=INKEY$
IF x$ <> "" THEN
SELECT CASE x$
CASE CHR$(0) + CHR$(72) 'Up arrow
position% = position% - 1
IF position% < 0 THEN position% = 0
CASE CHR$(0) + CHR$(80) 'Down arrow
position% = position% + 1
IF position% > 975 THEN position% = 975
CASE CHR$(0) + "I" 'Page Up
position% = position% - 24
IF position% < 0 THEN position% = 0
CASE CHR$(0) + "Q" 'Page Down
position% = position% + 24
IF position% > 975 THEN position% = 975
CASE CHR$(27) 'ENDS the Program on ESC key.
END
END SELECT
FOR i = 1 to 25
LOCATE i, 1: PRINT text(i + position%); SPACE$(80 - LEN(text(i + position%)));
NEXT i
END IF
LOOP
Tested and works! If you want to use it multiple times in your program for multiple different text blocks, you can just turn it into a function and pass it the variables you want.
I have 2 txt files with different strings and numbers in them splitted with ;
Now I need to subtract the
((number on position 2 in file1) - (number on position 25 in file2)) = result
Now I want to replace the (number on position 2 in file1) with the result.
I tried my code below but it only appends the number in the end of the file and its not the result of the calculation which got appended.
def calc
f1 = File.open("./file1.txt", File::RDWR)
f2 = File.open("./file2.txt", File::RDWR)
f1.flock(File::LOCK_EX)
f2.flock(File::LOCK_EX)
f1.each.zip(f2.each).each do |line, line2|
bg = line.split(";").compact.collect(&:strip)
bd = line2.split(";").compact.collect(&:strip)
n = bd[2].to_i - bg[25].to_i
f2.print bd[2] << n
#puts "#{n}" Only for testing
end
f1.flock(File::LOCK_UN)
f2.flock(File::LOCK_UN)
f1.close && f2.close
end
Use something like this:
lines1 = File.readlines('file1.txt').map(&:to_i)
lines2 = File.readlines('file2.txt').map(&:to_i)
result = lines1.zip(lines2).map do |value1, value2| value1 - value2 }
File.write('file1.txt', result.join(?\n))
This code load all files in memory, then calculate result and write it to first file.
FYI: If you want to use your code just save result to other file (i.e. result.txt) and at the end copy it to original file.
I have an excel output in the tab-delimited format:
temperature H2O CO2 N2 NH3
10 2.71539E+12 44374931376 7410673406 2570.560804
20 2.34216E+12 38494172272 6429230649 3148.699673
30 2.04242E+12 33759520581 5639029060 3856.866413
40 1.75491E+12 29172949817 4882467457 4724.305292
.
.
.
I need to convert these numbers to FORMAT(1X,F7.0,2X,1P4E11.3) readable for another code.
This is what I've come up with:
program fixformat
real temp, neuts(4)
integer i,j
character header
open(11,file='./unformatted.txt',status='old')
open(12,file='./formatted.txt',status='unknown')
read(11,*) header
write(12,*) header
do i = 1, 200
read(11,*) temp, (neuts(j),j=1,4)
write(12,23) temp, (neuts(j),j=1,4)
end do
23 FORMAT(1X,F7.0,2X,1P4E11.3)
close(11)
close(12)
return
end
I keep getting this error:
Fortran runtime error: Bad real number in item 1 of list input
Is there any other way to convert the data to that format?
You need a character string, not a single character for the header
character(80) header
other than that you program works for me. Make sure you have the right number of lines in your loop
Do i=1,200
Adjust 200 to the real number of your data lines.
If for some reason you still cannot read even a single line, you can also use the format:
read(11,'(f2.0,4(1x,f11.0))') temp, (neuts(j),j=1,4)
because the tab is just a character you can easily skip.
Notes:
Unformatted and formatted means something completely different in Fortran. Unformatted is what you may know as "binary".
Use some indentation and blank lines for your programs to make them readable.
There is no reason to explicitly use status=unknown. Just don't put anything there. In your case status=replace may be more appropriate.
The FORMAT statement is quite obsolete, in modern Fortran we use format strings:
write(12,'(1X,F7.0,2X,1P4E11.3)') temp, (neuts(j),j=1,4)
There is absolutely no reason for your return before the end. Returns is for early return from a procedure. Some put stop before the end program, but it is superfluous.
To read tab delimited data, I'd use a simple algorithm like the one below. NOTE: This is assuming that there is no tab character in any of your fields.
integer :: error_code, delim_index, line_index
character*500 :: data_line, field_data_string
double precision :: dp_value
Open(Unit=1001,File="C:\\MY\\PATH\\Data.txt")
DO
Read(UNIT=1001,End=106, FMT='(A)' ) data_line
line_length = LEN(TRIM(data_line))
delim_index = SCAN(data_line, achar(9) )
line_index = 0
DO WHILE ( delim_index .NE. 0 )
line_index = line_index + delim_index
IF (delim_index .EQ. 1 ) THEN ! found a NULL (no value), so skip
GOTO 101
END IF
field_data_string = data_line( (line_index-delim_index+1) : line_index )
READ( field_data_string, FMT=*, ERR=100) dp_value
PRINT *, "Is a double precision ", dp_value
GOTO 101
100 Continue
PRINT *, "Not a double precision"
101 Continue
IF ( (line_index+1) .GT. line_length ) THEN
GOTO 104 ! found end of line prematurely
END IF
delim_index = SCAN( data_line( line_index + 1 : ), achar(9) )
END DO
field_data_string = data_line( line_index + 1 : )
READ( field_data_string, FMT=*, ERR=102) dp_value
PRINT *, "Is a double precision ", dp_value
GOTO 103
102 Continue
PRINT *, "Not a double precision"
103 Continue
PRINT *, "Is a double precision ", dp_value
104 Continue
END DO
104 Continue
PRINT *, "Error opening file"
105 Continue
Close(1001)
I have a relatively big text file with blocks of data layered like this:
ANALYSIS OF X SIGNAL, CASE: 1
TUNE X = 0.2561890123390808
Line Frequency Amplitude Phase Error mx my ms p
1 0.2561890123391E+00 0.204316425208E-01 0.164145385871E+03 0.00000000000E+00 1 0 0 0
2 0.2562865535359E+00 0.288712798671E-01 -.161563284233E+03 0.97541196785E-04 1 0 0 0
(they contain more lines and then are repeated)
I would like first to extract the numerical value after TUNE X = and output these in a text file. Then I would like to extract the numerical value of LINE FREQUENCY and AMPLITUDE as a pair of values and output to a file.
My question is the following: altough I could make something moreorless working using a simple REGEXP I'm not convinced that it's the right way to do it and I would like some advices or examples of code showing how I can do that efficiently with Ruby.
Generally, (not tested)
toggle=0
File.open("file").each do |line|
if line[/TUNE/]
puts line.split("=",2)[-1].strip
end
if line[/Line Frequency/]
toggle=1
next
end
if toggle
a = line.split
puts "#{a[1]} #{a[2]}"
end
end
go through the file line by line, check for /TUNE/, then split on "=" to get last item.
Do the same for lines containing /Line Frequency/ and set the toggle flag to 1. This signify that the rest of line contains the data you want to get. Since the freq and amplitude are at fields 2 and 3, then split on the lines and get the respective positions. Generally, this is the idea. As for toggling, you might want to set toggle flag to 0 at the next block using a pattern (eg SIGNAL CASE or ANALYSIS)
file = File.open("data.dat")
#tune_x = #frequency = #amplitude = []
file.each_line do |line|
tune_x_scan = line.scan /TUNE X = (\d*\.\d*)/
data_scan = line.scan /(\d*\.\d*E[-|+]\d*)/
#tune_x << tune_x_scan[0] if tune_x_scan
#frequency << data_scan[0] if data_scan
#amplitude << data_scan[0] if data_scan
end
There are lots of ways to do it. This is a simple first pass at it:
text = 'ANALYSIS OF X SIGNAL, CASE: 1
TUNE X = 0.2561890123390808
Line Frequency Amplitude Phase Error mx my ms p
1 0.2561890123391E+00 0.204316425208E-01 0.164145385871E+03 0.00000000000E+00 1 0 0 0
2 0.2562865535359E+00 0.288712798671E-01 -.161563284233E+03 0.97541196785E-04 1 0 0 0
ANALYSIS OF X SIGNAL, CASE: 1
TUNE X = 1.2561890123390808
Line Frequency Amplitude Phase Error mx my ms p
1 1.2561890123391E+00 0.204316425208E-01 0.164145385871E+03 0.00000000000E+00 1 0 0 0
2 1.2562865535359E+00 0.288712798671E-01 -.161563284233E+03 0.97541196785E-04 1 0 0 0
ANALYSIS OF X SIGNAL, CASE: 1
TUNE X = 2.2561890123390808
Line Frequency Amplitude Phase Error mx my ms p
1 2.2561890123391E+00 0.204316425208E-01 0.164145385871E+03 0.00000000000E+00 1 0 0 0
2 2.2562865535359E+00 0.288712798671E-01 -.161563284233E+03 0.97541196785E-04 1 0 0 0
'
require 'stringio'
pretend_file = StringIO.new(text, 'r')
That gives us a StringIO object we can pretend is a file. We can read from it by lines.
I changed the numbers a bit just to make it easier to see that they are being captured in the output.
pretend_file.each_line do |li|
case
when li =~ /^TUNE.+?=\s+(.+)/
print $1.strip, "\n"
when li =~ /^\d+\s+(\S+)\s+(\S+)/
print $1, ' ', $2, "\n"
end
end
For real use you'd want to change the print statements to a file handle: fileh.print
The output looks like:
# >> 0.2561890123390808
# >> 0.2561890123391E+00 0.204316425208E-01
# >> 0.2562865535359E+00 0.288712798671E-01
# >> 1.2561890123390808
# >> 1.2561890123391E+00 0.204316425208E-01
# >> 1.2562865535359E+00 0.288712798671E-01
# >> 2.2561890123390808
# >> 2.2561890123391E+00 0.204316425208E-01
# >> 2.2562865535359E+00 0.288712798671E-01
You can read your file line by line and cut each by number of symbol, for example:
to extract tune x get symbols from
10 till 27 on line 2
to extract LINE FREQUENCY get
symbols from 3 till 22 on line 6+n