I need to split a name based on space character i.e.,
if name = "abc defgh ijk" then
fname should have "abc"
mname should have "defgh"
lname should have "ijk".
Please give me some code by which i can achieve this.
What have you tried yourself?
Anyway, locating a space and getting the length is rather trivial, one method:
Code:
la 1,string -> start
a ahi 1,1 bump ptr
cli 0(r1),c' ' test
jne a continue if not blank
la 2,string -> start
sr 1,2 get length of word
bctr 1,0 machine length of word
mvc out(*-*),string
ex 1,*-6 do copy
Note that it does not handle when the string starts with one or more blanks, nor does it check for string end. I leave that as an exercise to the OP. The MVC is executed twice, does it matter - perhaps.
Assembler purists will insist that you use the TRT intruction, but I think that the above is easier to understand.
I have written a couple of macros to count words and get words from a string, aka the REXX WORD and WORDS functions.They are available upon request.
What have you tried yourself?
Anyway, locating a space and getting the length is rather trivial, one method:
Code:
la 1,string -> start
a ahi 1,1 bump ptr
cli 0(r1),c' ' test
jne a continue if not blank
la 2,string -> start
sr 1,2 get length of word
bctr 1,0 machine length of word
mvc out(*-*),string
ex 1,*-6 do copy
Note that it does not handle when the string starts with one or more blanks, nor does it check for string end. I leave that as an exercise to the OP. The MVC is executed twice, does it matter - perhaps.
Assembler purists will insist that you use the TRT intruction, but I think that the above is easier to understand.
I have written a couple of macros to count words and get words from a string, aka the REXX WORD and WORDS functions.They are available upon request.
Joined: 30 Nov 2013 Posts: 917 Location: The Universe
The OP left out important details
Max length of any substring?
What if a substring > max expected length?
What if there are too many substrings?
What do I do with the substrings?
Without these details we cannout produce realistic code.
As for TRT (or more realistically, SRST) the code as set forth by Mr. Jensen is more readable, though slightly slower that code written to use TRT or SRST.
Today I'm in good mood, so trying to re-call this exercise from my head.
Lazy to test it; hope there is no serious bug.
Code:
. . . . .
LA R3,FULLNAME start of original field
LA R15,FULLNAME+L'FULLNAME limit to scan - end of field
LA R2,FNAME place for the first name
LHI R0,+3 the number of names to find
MVC FNAME,=CL15' ' cleanup output fields
MVC MNAME,=CL15' ' cleanup output fields
MVC LNAME,=CL15' ' cleanup output fields
* skip initial and/or intermediate spaces
LOOPWORD LR R1,R3 running pointer, set to end of previous name
FINDSTRT CLI 0(R1),C' ' check for name start
JNE SCANNAME when found - then look for name end
LA R1,1(R1) shift to next character
CR R1,R15 prevent over-parsing after field end
JL FINDSTRT continue check for name start
J STOPSCAN end of input field - stop everything
* find single name
SCANNAME LR R3,R1 remember the start of current name
FINDEND CLI 0(R1),C' ' look for name-end
JE COPYNAME when found - copy it to output field
LA R1,1(R1) shift to next character
CR R1,R15 prevent over-parsing after field-end
JL FINDEND continue looking for name end
* copy name part to its place
COPYNAME SR R1,R3 real length of the scanned name
LA R3,0(R1,R3) reset to the end of the scanned name
CHI R1,L'FNAME compare to field size
JLE GOODSIZE
LHI R1,L'FNAME truncate to allowed size
GOODSIZE EQU *
BCTR R1,0 length minus 1, for MVC
EX R1,MOVENAME copy the scanned name part
LA R2,L'FNAME(R2) be ready to take the next name
BCT R0,LOOPWORD if less than 3 names, then repeat the exercise
STOPSCAN EQU *
* continue here with all split names (either 3 or less, if not present)
. . . . .
. . . . .
MOVENAME MVC 0(0,R2),0(R3) template for copy name part
. . . . .
FULLNAME DC CL30'John V Ripper'
. . . . .
FNAME DS CL15
MNAME DS CL15
LNAME DS CL15
Joined: 30 Nov 2013 Posts: 917 Location: The Universe
A more complete example, using BXLE/JXLE/BRXLE for loop control.
Code:
SPLIT CSECT
USING *,12
SAVE (14,12),,*
LR 12,15
LR 15,13
LA 13,SAVEAREA
ST 15,4(,13)
ST 13,8(,15)
LA 3,STRING
LA 4,1
LA 5,STRINGE
LA 7,NAMES
LA 8,L'NAMES
LA 9,LASTNAME
A CLI 0(3),C' '
JNE B
JXLE 3,4,A
J F
B LR 14,3
C CLI 0(3),C' '
JE D
JXLE 3,4,C
D LR 15,3
SR 15,14
JP E
DC H'0'
E LR 0,7
LR 1,8
ICM 15,B'1000',=C' '
MVCL 0,14
JXLE 7,8,A
F NOPR 0
L 13,4(,13)
RETURN (14,12),RC=0
SAVEAREA DC 9D'0'
LTORG ,
NAMES DC 3CL15' '
LASTNAME EQU *-L'NAMES
STRING DC CL80' JAMES E DOE'
STRINGE EQU *-1
END SPLIT
The example handles leading blanks correctly. The S0C1 ABEND executes if a substring length is <= 0 bytes, which should never happen. The MVCL inserts trailing blanks in each substring name, which the EX reg,MVC in Mr. Jensen's and Sergyken's samples do not do. FWIW, it did work, on the second try (and 3 assemblies).
In some ways it's not very realistic. It uses 6 registers for loop control, plus another 4 for the MVCL, though most code critics agree registers 14, 15, 0 and 1 are not all that useful much of the time. My code uses them for this purpose quite often. MVCL / CLCL can use an address in reg 0, which most instructions cannot do.
Yesterday I supposed that the dream of the TS was something like this:
Code:
. . . . .
WORDSCAN FROM=FULLNAME,TO=XNAMES,WORDS=3
. . . . .
FULLNAME DC CL50' Frank John Fitzgerald'
. . . . .
XNAMES DS 3CL15 space for 3 output names
. . . . .
But my yesterday's message was removed by moderators, though my intention was to inspire someone to present something similar to that solution.
Since my attempt is not appreciated, I try to do it myself.
Code:
MACRO
&NAME WORDSCAN &FROM=,&TO=,&WORDS=1
**========================================================
** The macro to split a character string by words
** Registers 0, 1, 14, and 15 are used as working storage
**========================================================
&NAME LA 14,&FROM start of original field
LA 15,&TO place for the first name
LHI 0,&WORDS the number of names to find
* skip leading and/or intermediate spaces
L&SYSNDX LR 1,14 running pointer, set to end of previous name
B&SYSNDX CLI 0(1),C' ' check for name start
JNE S&SYSNDX when found - then look for name end
LA 1,1(1) shift to next character
CL 1,=A(&FROM+L’&FROM) prevent over-parsing after field end
JL B&SYSNDX continue check for name start
J X&SYSNDX end of input field - stop everything
M&SYSNDX MVC 0(0,15),0(14) template for copy name part
* find single name
S&SYSNDX LR 14,1 remember the start of current name
E&SYSNDX CLI 0(1),C' ' look for name-end
JE C&SYSNDX when found - copy it to output field
LA 1,1(1) shift to next character
CL 1,=A(&FROM+L’&FROM) prevent over-parsing after field-end
JL E&SYSNDX continue looking for name end
* copy name part to its place
C&SYSNDX SR 1,14 real length of the scanned name
AR 14,1 remember the end of the scanned name
CHI 1,L’&TO compare to output field size
JLE G&SYSNDX
LHI 1,L’&TO truncate to allowed size
G&SYSNDX EQU *
MVC 0(L'&TO,15),=CL(L'&TO)' ' cleanup output field
BCTR 1,0 length minus 1, for MVC
EX 1,M&SYSNDX copy the scanned name part
LA 15,L’&TO.(15) be ready to take the next name
BCT 0,L&SYSNDX if less than WORDS number, then repeat the exercise
X&SYSNDX EQU *
* continue here with all split names (either &WORDS or less, if not present)
MEND
@sergeyken, "inspire someone to present something similar"
Ok, here is my take. An external macro SETREG is required and is available at harders-jensen.com
@sergeyken, "inspire someone to present something similar"
Ok, here is my take. An external macro SETREG is required and is available at harders-jensen.com
My initial version was created at-hoc, just as an improvisation.
Other suggested variants seem to be the product of real development. Nevertheless, I believe that the extra customizability does not worth the result; it allows this macro to be used with explicit addressing (via registers), etc. which is not appreciated in a good-style development.
After thinking a little bit about my initial version I found one drawback: if too few actual words are presented on input, then the rest of output fields are not cleaned-up. So, I slightly updated it as follows.
Code:
MACRO
&NAME WORDSCAN &FROM=,&TO=,&WORDS=1
**========================================================
** The macro to split a character string by words
** Registers 0, 1, 14, and 15 are used as working storage
**========================================================
&NAME LA 14,&FROM start of original field
LA 15,&TO place for the first name
LHI 0,&WORDS the number of names to find
* start loop on every single word
L&SYSNDX EQU *
* cleanup output field
MVI 0(15),C’ ‘ clean first output byte
MVC 1(L’&TO-1,15),0(15) clean full output field
* skip leading and/or intermediate spaces
LR 1,14 running pointer, set to end of previous name
B&SYSNDX CLI 0(1),C' ' check for name start
JNE S&SYSNDX when found - then look for name end
LA 1,1(1) shift to next character
CL 1,=A(&FROM+L’&FROM) prevent over-parsing after field end
JL B&SYSNDX continue check for name start
BCTR 1,0 shift pointer back when out of string
J X&SYSNDX end of input field - stop scan this name
M&SYSNDX MVC 0(0,15),0(14) template for copy name part
* find single name
S&SYSNDX LR 14,1 remember the start of current name
E&SYSNDX CLI 0(1),C' ' look for name-end
JE C&SYSNDX when found - copy it to output field
LA 1,1(1) shift to next character
CL 1,=A(&FROM+L’&FROM) prevent over-parsing after field-end
JL E&SYSNDX continue looking for name end
* copy name part to its place
C&SYSNDX SR 1,14 real length of the scanned name
AR 14,1 remember the end of the scanned name
CHI 1,L’&TO compare to output field size
JLE G&SYSNDX
LHI 1,L’&TO truncate to allowed size
G&SYSNDX EQU *
BCTR 1,0 length minus 1, for MVC
EX 1,M&SYSNDX copy the scanned name part
X&SYSNDX EQU *
LA 15,L’&TO.(15) be ready to take the next name
BCT 0,L&SYSNDX if less than WORDS number, then repeat the exercise
* continue here with all split names (either &WORDS or less, if not present)
MEND