I have a two requirements:
I must concatenate some fields from a file in a Cobol program. The way i must concatenate is based on one of the aforementioned field. The concatenated fields must be outputted in a new file.
I must then sort this new file with a sort utility invoked by JCL.
The Issue
I need to sort same file for 2 conditions. I have tried with ifthen outrec build. How can I sort it in one pass?
Here is a source-code example :
ID DIVISION.
PROGRAM-ID. FOO.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
Select Infil assign to inp001.
Select Outfil assign to out001.
DATA DIVISION.
FILE SECTION.
FD Infil.
01 Main.
03 A.
05 ws-Pc. Pic x(1).
05 filler Pic x(5).
03 B. Pic x(4).
03 C. Pic x(4).
03 D. Pic 9(13)V99.
03 E. Pic x(13).
FD Outfil.
01 Temp Pic x(42).
WORKING-STORAGE SECTION.
01 file-flag Pic x(01).
88 file-end value 'Y'.
88 not-file-end value 'N'.
PROCEDURE DIVISION.
Open input Infil
Open output Outfil
read Infil
at end
set file-end to true
not at end
set not-file-end to true
end-read
Perform until file-end
If ws-Pc = 3
String A B C Delimited by size
into Temp
End-String
Else
String A B C E Delimited by size
into Temp
End-String
End-if
Write Temp
read Infil
at end
Set file-end to true
end-read
end-Perform.
end program foo.
Here is the logic I need for the sort utility :
If ws-Pc=3
Sort(fieldA,fieldB)
Else
Sort(fieldA,fieldB,fieldE)
End-if.
I can propose you three variations :
If you are sure that your last 13 characters are the same (spaces for instance) in the case without a field E (ws-pc equal to three) you can just have this sysin:
SORT FIELDS=(1,6,CH,A,7,4,CH,A),EQUALS
Indeed, thanks to the equals all your inputs will keep their relative order once sorted. For the case ws-pc=3 it will be sorted according to field A and B. Field E plays no importance because it is the same for all.
If you are not sure that the last 13 characters are the same you can do it yourself:
INREC IFTHEN=(WHEN=(1,1,CH,EQ,C'3'),BUILD=(1,14,13X))
SORT FIELDS=(1,6,CH,A,7,4,CH,A),EQUALS
This will force your last characters to be spaces.
If you don't want to use the "EQUALS" you can create your own ordering by appending a line number in the field E when it is unused. You then have to remove it.
INREC IFTHEN=(WHEN=(1,1,CH,EQ,C'3'),BUILD=(1,14,SEQNUM,13,ZD))
SORT FIELDS=(1,6,CH,A,7,4,CH,A)
OUTREC IFTHEN=(WHEN=(1,1,CH,EQ,C'3'),BUILD=(1,14,13X))
Given a number of JSON files in a directory, I need to extract the names of those that contain, in a line labeled "keyword:", a combination of words that match a Boolean query.
For example:
file 01 contains the line:
...
"keyword": "Alabama", "Washington"
...
file 02 contains the line:
...
"keyword": "Washington", "Pennsylvania"
...
this is how the search should work:
$ query "Washington"
01
02
$ query "Washington & !Alabama"
02
$ query "Alabama | Pennsylvania"
01
02
and so on, for any Boolean combination of individual keys, say
query "(Alabama & !California) | Maine"
grep "keyword" <directory> will extract the lines of interest, and the rest can be pipelined from there, but grep implementations of logical operators differ much from Boolean expressions, and awk, while getting closer in its syntax, doesn't seem to work for me (may be I haven't dedicated enough time to it).
What would be a good candidate to implement this functionality, and how to translate to such an intuitive syntax?
I am trying to right and left outer join these two RECFM VB files but
I don't get anything from the F2 file.
//STEP2000 EXEC PGM=SORT
//* JOIN
//*
//SYSOUT DD SYSOUT=*
//*
//SORTJNF1 DD DSN=YXX122.TEMP.EXPORT.TYPEN,
// DISP=SHR
//*
//SORTJNF2 DD DSN=YXX122.TEMP.EXPORT.TYPEC,
// DISP=SHR
//*
//SORTOUT DD DSN=YXX122.DYXX122.EXPORT.XSUM,
// DISP=(NEW,CATLG,DELETE),
// UNIT=(DEV,2),
// SPACE=(CYL,(150,20),RLSE),
// DCB=(RECFM=VB,LRECL=304,BLKSIZE=0)
//*
//SYSIN DD *
SORT FIELDS=COPY
JOINKEYS FILES=F1,
FIELDS=(13,4,A,18,5,A,17,1,A,23,1,A,33,8,A,41,4,A)
JOINKEYS FILES=F2,
FIELDS=(13,4,A,18,5,A,17,1,A,23,1,A,33,8,A,41,4,A)
JOIN UNPAIRED,F1,F2
REFORMAT FIELDS=(F1:5,300)
OUTFIL FTOV
//
The problem is I can't find how the REFORMAT FIELDS the F2 file.
I tried with REFORMAT FIELDS=(F1:5,300,F2:5,300) but the outfile was with a length of 600.
I will like to know how to have both file F1 and F2 in my SORTOUT file with a VB length 304.
Any idea on how to fix this problem?
It turns out you have DFSORT, not SyncSORT which makes things simpler, as you can definitely use the Match Marker ? in the REFORMAT statement. Up-to-date SyncSORT may have the Match Marker as an undocumented feature.
Putting all the unmatched records on one OUTFIL may be confusing (you won't know which input they have come from).
This conceptualises your join (where the Output is the joined data, and b represents blank).
F1
A
C
E
F2
B
C
F
Output
Ab
bB
Eb
bF
So if you want B and F you need to specify some data from F2. You also need to identify the "blanks" so that you know which part of the REFORMAT record currently has data in (DFSORT has a Match Marker for this, SyncSORT does not).
For that you need to identify one byte which can never be blank in the record. If that is not possible, one byte which can never be another given value (which you specify on FILL= on the REFORMAT). Failing that, two or more bytes with the same characteristics. As a final fail-safe you can check the entire part of the REFORMAT record from one file or the other for blank.
Since you want V-type output, you could make your REFORMAT record variable:
REFORMAT FIELDS=(F1:1,4,?,F1:5,300,F2:5)
And use VLTRIM on OUTFIL.
Or fixed:
REFORMAT FIELDS=(F1:5,300,F2:5,300)
And use FTOV with VLTRIM on OUTFIL.
Then you need some code, which tests the byte/bytes/partofdata you have chosen for being space/thevalueyouhavechosen and uses BUILD to create a record which contains the data you want (plus trailing blanks/values which will be killed by the VLTRIM).
IFTHEN=(WHEN=(logicalexpression),
BUILD=(1,4,5,300)),
IFTHEN=(WHEN=NONE,
BUILD=(1,4,305,300))
Or
IFTHEN=(WHEN=(logicalexpression),
BUILD=(1,300)),
IFTHEN=(WHEN=NONE,
BUILD=(301,300))
Here's some code which does what you want. Probably. I can't test it with SyncSORT.
Data:
F1
A 11111111111111111111111111111111111
C 2222222222222222222222
E 3
F2
B 4444444444444444
C 55555555555555555555555555
F 6666666666666
Code:
OPTION COPY
JOINKEYS F1=INA,FIELDS=(5,1,A),SORTED,NOSEQCK
JOINKEYS F2=INB,FIELDS=(5,1,A),SORTED,NOSEQCK
JOIN UNPAIRED,F1,F2,ONLY
REFORMAT FIELDS=(F1:1,4,F1:5,76,F2:5)
OUTFIL FNAMES=EXT,VLTRIM=C' ',
IFTHEN=(WHEN=(81,1,CH,EQ,C'2'),
BUILD=(1,4,82)),
IFTHEN=(WHEN=NONE,
BUILD=(1,4,5,76))
The Match Marker, ?, will be set to 1 for unmatched F2, 2 for unmatched F2 and B for matched records (which you won't get, because of the ONLY on the JOIN statement).
This presumes your data is already in sequence. Remove the SORTED,NOSEQCK for data which is not in sequence.
I've used an LRECL of 80 and a simple key and some simple data.
Output:
For EXT:
A 11111111111111111111111111111111111
B 4444444444444444
E 3
F 6666666666666
SORTOUT would show the unchanged REFORMAT record. That is for you to see how it works. You can remove the FNAMES=EXT or remove the SORTOUT from the JCL when you understand everything.
The F1:1,4 ensures that the REFORMAT record is variable-length. The 5,300 should use blank-padding for shorter records. That's why you need the VLTRIM later. The F2:5 says "file two, position five, to the end of the file two record".
If your data can have genuine trailing blanks, you'll have to use FILL= and VLTRIM= for the same character.
IFTHEN=(WHEN=(logicalexpression) processing finishes when an IFTHEN is true. So the combination in the code is effectively an IF/ELSE.
See also this, Compare two files and write it to "match" and "nomatch" files and Sync sort, Unpaired records of File1 have spaces for no records in F2 file. Can we replace those specific column's spaces by ZEROS? for further examples.
how can I split this barcode by group separator with Progress? I've tried chr(29) without any luck.
Barcode scanned into Notepad++: http://i.imgur.com/8DmPZ.png
Barcode scanned into input field: 2409271405202120330017100282
Thanks.
def var c as char no-undo.
def var i as int no-undo.
update c format "x(50)".
do i = 1 to length(c):
message substr(c, i, 1) = chr(29).
end.
The problem is that GS is an undefined control code. So you need to make it be recognized.
Add the following to your terminal's entry in protermcap to define GS as F13:
:(F13)=\035:\
(The octal code for GS is \035 and F13 is an undefined function key -- so the combination should work. I don't have a scanner to test with but this works for the control codes that I can type into my keyboard...)
Then use code like this:
define variable bc as character no-undo format "X(50)".
update bc editing:
if lastkey = 313 then
apply ".". /* 313 is the code for F13 */
else
apply lastkey.
end.
This should cause "." to be inserted instead of GS. Which will allow you to parse the string using "." rather than GS.
It's a wild guess, but I'm thinking ENTRY(entry-num, barcode-string, "group-separator-string")?
This works for me:
/* create a test file (otherwise not needed...)
*/
output to "barcode.dat".
put control "240927140520" chr(29) "2120330017" chr(29) "100282".
output close.
/* if you already have barcode.dat start here
*/
define variable m as memptr no-undo.
define variable bc as character no-undo.
set-size( m ) = 100.
input from "barcode.dat" binary no-convert.
import unformatted m.
input close.
bc = get-string( m, 1 ).
display
entry( 1, bc, chr(29)) format "x(12)" skip
entry( 2, bc, chr(29)) format "x(12)" skip
entry( 3, bc, chr(29)) format "x(12)" skip
.
I have a bunch of input files in a loop and I am extracting tag from them. However, I want to separate some of the words. The incoming strings are in the form cs### where ### => is any number from 0-9. I want the result to be cs ###. The closest answer I found was this, Regex to separate Numeric from Alpha . But I cannot get this to work, as the string is being predefined (Static) and mine changes.
Found answer:
Nevermind, I found the answer the following sperates alpha-numeric characters and removes any unwanted non-alphanumeric characters so anything like ab5#6$% =>ab 56
gsub(/(?<=[0-9])(?=[a-z])|(?<=[a-z])(?=[0-9])/i, ' ').gsub(/[^0-9a-z ]/i, ' ')
If your string is something like
str = "cs3232
cs23
cs423"
Then you can do something like
str.scan(/((cs)(\d{1,10}))/m).collect{|e| e.shift; e }
# [["cs", "3232"], ["cs", "23"], ["cs", "423"]]