I’m wanting to write a Function that will receive a string and determine if there are “invalid” characters in the string. I’d like the Function to handle flexible string sizes (dynamic) but the calling program shouldn’t have to define it’s string as dynamic. For example.
program
0001 DEFINE DATA LOCAL
0002 1 #STR (A25) INIT <'ABC$123'>
0003 END-DEFINE
0004 *
0005 DEFINE PROTOTYPE HAS_INVALID_CHARS RETURNS (L)
0006 DEFINE DATA PARAMETER UNKNOWN
0007 END-DEFINE
0008 END-PROTOTYPE
0009 *
0010 IF HAS_INVALID_CHARS(<STR>)
0011 write 'This string has invalid characters.'
0012 END-IF
0013 END
Note to web master: In line 10 above, the message editor removed a # before STR.
function
0001 DEFINE FUCNTION HAS_INVALID_CHARS RETURNS (L)
0002 DEFINE DATA PARAMETER
0003 1 #PARM-STRING (A) DYNAMIC
0004 LOCAL
...
0009 END-DEFINE
...determine if string contains any specific special characters. I need more power than using MASK(S)
0013 IF #INVALID
0014 MOVE #INVALID TO HAS_INVALID_CHARS
0015 END-IF
0016 END-FUNCTION
0017 END
The problem: I’m getting a runtime error (NAT0969) indicating that the parameters don’t match.
Yes, I could define a dynamic string (#str-d) in the program, move #str to #str-d, then pass #str-d to the function but that reduces the power using the function.
Any ideas?
By the way, Functions are awesome and if you’re not using them yet, you need to take a good look at them.
I was interested to see your post, as I have written a function recently which provides extended MASK functionality for just this kind of purpose. In case you might find it helpful I’ve attached it to a post in the Natural Code Samples forum section.
Here are the extended mask characters it provides:
* @ = Any letter or digit, but not space
* ^ = Space
* + = Tab
* | = Any of the delimiters Tab, Pipe, Comma or Semi-Colon.
* - = Any of the date format delimiters Dash, Slash or Period.
* {} = Hex string eg {0D0A09} = carriage return, line feed, tab
* ~ = Any number (or none) of the next mask char.
* Can be followed by m[:n] where m and n
* are the min and max number of the char to find:
* ~0x is the same as ~x
* ~1x is at least one of the mask character x
* ~2:5x scans for 2 to 5 instances of the character x
* Note that this test finds the longest match it can.
* Therefore, without a max, the subsequent mask test char
* (after x) must not be a subset of x, as this will fail,
* since all the string x's will have been passed by the ~x.
* ¬ = Any one char which is NOT the next mask char.
* Can be used with ~[m:n], eg ~1:2¬x
* (but not directly before the ~)
* [] = Optional characters, to be accepted if possible.
* Note that preceding mask chars are tested independently,
* whereas subsequent are tested together with the optional,
* so YY[YY] means YY, optionally followed by another YY,
* whereas [YY]YY means either YY or YYYY.
* $ = User-defined set of characters
*
* Mask Examples:
*
* ¬A Any character except a letter.
* ~@ Any letters or digits.
* ~¬C Any chars which are not letters or digits or space.
* ~^~$ Any spaces, then any chars which are in Set.
* ¬$ Not a Set char,
* e.g. if Set = '+-*/=' then any char but +-*/=
* ~1¬@ One or more chars which are not letters or digits.
* *A¬/ String contains a letter which is not at the end.
* *P{0D}P String contains a carriage return
* surrounded by printable characters.
*
* Call Examples:
*
* 1. IF MASK$( #String,'*|*¬|/' )
*
* is TRUE if #String contains a delimiter,
* and does not end with a delimiter.
*
* 2. IF MASK$( #String,'~1:5$/','"AEIOUaeiou"' )
*
* is TRUE if #String contains 1 to 5 vowels only.
*
* 3. IF MASK$( #String,'*DD-MM-[YY]YY',,50,20 )
*
* is TRUE if SUBSTRING(#String,50,20)
* contains a date as dd,mm,yy or yyyy
* separated by dashes, slashes or periods.
*
* 4. RESET #S #L
* IF MASK$( #String,'*U*","N',,#S,#L )
*
* is TRUE if #String contains an upper case letter
* followed later by a comma & digit.
* #S returns the position of U in the string
* and #L returns the length
* from U to first ,N inclusive.