Checking strings in Genexus RPG via RegEx - rpgle

We have a "string" / Character(15) variable which we need to validate characters 5 through 10 are numbers. This is pretty straightforward when writing raw code and using regular expressions, or when using Genexus to build Java objects, but we are using Genexus and building to RPG IV.
I'm relatively new (less than a year) to this platform, so I'm not sure how to do this. I'm told that the regex functionality in the version Genexus we use doesn't work for RPG. My suggestion to pull a substring and get the val() of it will cause an error if it's not all numbers, halting the program. Apparently, there's no way to gracefully handle the error in our version Genexus/RPGLE.
Does anyone have experience dealing with this? Can someone point us in a good direction, using Genexus for RPG, to resolve this issue?

You may write a procedure that does the checking "by hand".
i.e.:
&str = '1234567890ABCDEF' // this would be the input string
&isValid = 1 // this would be the output
if len(&str) > 9
for &index = 5 to 10
&char = substr(&str, &index, 1)
do case
case &char = '0'
case &char = '1'
case &char = '2'
case &char = '3'
case &char = '4'
case &char = '5'
case &char = '6'
case &char = '7'
case &char = '8'
case &char = '9'
otherwise
&isValid = 0
exit
endcase
endfor
else
&isValid = 0
endif

Related

How to determine the end of string in VFP 9?

In some programming languages, such as C for example, the end of string may be marked as a separate null terminator symbol.
How do I determine if the current symbol is the end of string?
Currently I use some string functions' calls, but I guess it may be performed easier.
*the string's end
IF ISBLANK(SUBSTR(str, pos, 1) == .T. AND CHR(32) != SUBSTR(str, pos, 1)
RETURN .T.
ENDIF
There's no need to worry about C-style string termination in VFP.
Assuming you don't care what the last character is then from your example:
return (pos = len(str))
If you want to ignore spaces:
return (pos = len(alltrim(str))
VFP strings are not ASCIIZ strings as in C. A VFP string can contain any ASCII character including character 0 - chr(0)- which is a string termination character in C style languages.
Normally the end of the string in VFP is the same as its length. But, although it is not clear from your question, sometimes you get a string from a C source (ie: a win32 call) where multiple string values are separated by chr(0) values. You can easily parse such a string into multiple string with a code like alines(). ie:
? ALines(laLines, "hello"+Chr(0)+"there",1+4,Chr(0)) && prints 2
display memory like laLines && shows two string values
Also you could use many string function like at(), occurs(), asc() ... to locate, count ... that character.

Int32.TryParse equivalent for String?

I have been doing some homework. The task was to implement System.Int32.TryParse to check if an entered value is a number or something random. I was wondering if there is a built-in method that checks if something entered is a letter and NOT a number. I tried searching google and MSDN in the string type, but with no luck so far. I did write my own implementation, but I was curious.
Tnx
The easiest way to check whether a character is a number is probably to check whether it is in range from '0' to '9'. This works because of the way characters are encoded - the digits are encoded as a sub-range of the char values.
let str = "123"
let firstIsNumber =
str.[0] >= '0' && str.[0] <= '9'
This gives you a bit different behavior than Char.IsDigit because Char.IsDigit also returns true for thigns that are digits in other alphabets, say ႐႑႒႓႔႕႖႗႘႙ I suspect you do not plan to parse those :-).

Check if a string starts with a decimal digit?

It looks the following works, is it a good approach?
var thestr = "192.168.0.1"
if (thestr[0]>= '0' && thestr[0] <= '9'){
//...
}
Your solution is completely fine.
But note that strings in Go are stored as a read-only byte slice where the bytes are the UTF-8 encoded byte sequence, and indexing a string indexes its bytes, not its runes (characters). But since a decimal digit ('0'..'9') has exactly one byte, it is ok in this case to test the first byte, but first you should test if len(s) > 0 or s != "".
Here are some other alternatives, try all on the Go Playground:
1) Testing the byte range:
This is your solution, probably the fastest one:
s := "12asdf"
fmt.Println(s[0] >= '0' && s[0] <= '9')
2) Using fmt.Sscanf():
Note: this also accepts if the string starts with a negative number, decide if it is a problem for you or not (e.g. accepts "-12asf").
i := 0
n, err := fmt.Sscanf(s, "%d", &i)
fmt.Println(n > 0, err == nil) // Both n and err can be used to test
3) Using unicode.IsDigit():
fmt.Println(unicode.IsDigit(rune(s[0])))
4) Using regexp:
I would probably never use this as this is by far the slowest, but here it is:
r := regexp.MustCompile(`^\d`)
fmt.Println(r.FindString(s) != "")
Or:
r := regexp.MustCompile(`^\d.*`)
fmt.Println(r.MatchString(s))
Please do not use regexps for that simple task :)
What I would change in this case:
add check for empty string before checking for the first rune
I would rephrase it as "starts with a digit" as the number semantic is too broad. .5e-45 is a number, but probably it is not what you want. 0's semantic is also not simple: https://math.stackexchange.com/questions/238737/why-do-some-people-state-that-zero-is-not-a-number
Since you are comparing by character and no characters are between 1 and 9, I think your solution is ok, but it does not account for the other numbers following.
For example, if thestr was "192.something.invalid" it's no longer an IP.
I'd recommend using a regular expression to check the IP.
something like
\b(?:\d{1,3}\.){3}\d{1,3}\b

How to validate this string when we don't have the `|` operator in Lua?

I have strings of the form:
cake!apple!
apple!
cake!juice!apple!cake!
juice!cake!
In other words, these strings are composed of the three sub-strings "cake!", "apple!" and "juice!".
I need to validate these strings. The way to do this with a regular expression is thus:
/^(apple!|juice!|cake!)*$/
But Lua's patterns don't have the | operator, so it seemingly can't be done this way.
How can I validate my strings in Lua?
(I don't care about the contents of the strings: I only care about whether they conform (validate) or not.)
I know to write the code to do this but I can't think of a short way to do this. I'm looking for a short solution. I wonder if there's an elegant solution that I'm not aware of. Any ideas?
if str:gsub("%w+!", {["apple!"]="", ["juice!"]="", ["cake!"]=""}) == "" then
--do something
end
This solution uses a table as the second parameter to string.gsub. Since the patterns all match %w+, the table will validate for second time, only the real three patterns are replaced with an empty string. If after all the replacement, the string becomes empty, then the match succeeds.
Using a helper table variable can make it more clear:
local t = {["apple!"]="", ["juice!"]="", ["cake!"]=""}
if str:gsub("%w+!", t) == "" then
--do something
end
If there is a character that will never be in your string, for instance, the character "\1"(ASCII 1) is unlikely in a normal string, you can use this:
local str = "cake!juice!apple!cake!"
if str:gsub("apple!","\1"):gsub("juice!","\1"):gsub("cake!","\1"):gsub("\1","") == "" then
--do something
end
By replacing every match of the patterns to "\1", and finally replace "\1" to an empty string, the correct match would be an empty string in the end.
It has flaws(sometimes it's impossible to find a character that is never in the string), but I think it works in many situations.
The following seems to work for (the included) quick tests.
local strs = {
"cake!apple!",
"bad",
"apple!",
"apple!bad",
" apple!bad",
"cake!juice!apple!cake!",
"cake!juice! apple!cake!",
"cake!juice!badapple!cake!",
"juice!cake!",
"badjuice!cake!",
}
local legalwords = {
["cake!"] = true,
["apple!"] = true,
["juice!"] = true,
}
local function str_valid(str)
local newpos = 1
for pos, m in str:gmatch("()([^!]+!)") do
if not legalwords[m] then
return
end
newpos = pos + m:len()
end
if newpos ~= (str:len() + 1) then
return nil
end
return true
end
for _, str in ipairs(strs) do
if str_valid(str) then
print("Match: "..str)
else
print("Did not match: "..str)
end
end
Just to provide another answer, you can do this easily with lpeg's re module:
re = require 're'
local testdata =
{
"cake!apple!",
"apple!",
"cake!juice!apple!cake!",
"cake!juice!badbeef!apple!cake!",
"juice!cake!",
"badfood",
}
for _, each in ipairs(testdata) do
print(re.match(each, "('cake!' / 'apple!' / 'juice!')*") == #each + 1)
end
This outputs:
true
true
true
false
true
false
This looks almost like your regex pattern above minus the ^ $ of course since lpeg matching is always anchored.
Lua patterns are not a replacement for regular expressions, and cannot represent this sort of pattern. In this case, you just need to repeatedly make sure the front of the string matches one of your words and then pop it off, but you probably already knew that.
Something like:
local words = {cake=1,apple=2,juice=3}
local totals = {}
local matches = 0
local invalid = 0
string.gsub("cake!","(%a+)!",
function(word)
local index = words[word]
if index then
matches = matches + 1
totals[index] = totals[index] + 1
else
invalid = invalid + 1
end
end
)
if matches > 0 and invalid == 0 then
-- Do stuff
end
This will pass each word to the supplied function where you can validate each one.
I dont know if it'll help you to get by you problem. But using string.find() i could use "or". look:
str="juice!"
print(string.find(str, "cake!" or "teste"))
best regards

How to use String.format in groovy?

The code below prints the response variable preceded by spaces.
The number of spaces to be printed before the response variable is equivalent to the difference of the itemNumber and the examineeResponses.
Now, is it possible to pad the string with zero ("0") instead of spaces using String.format?
def converted = examineeResponses+String.format("%${itemNumber - 1}s", response)
Example using the above codes:
examineeResponses = '1' // String
itemNumber = 10 //int
response = '3' // String
Output:
" 3"
Desired output:
"000000003"
I believe you can do this, but it's a bit hard to understand your question:
int itemNumber = 10
String examineeResponses = '1'
char response = '3'
"$response".padLeft( itemNumber - examineeResponses.length(), '0' )
Though I suspect (you don't say) that you just want it printed itemNumbers characters wide. If this is the case, you just need:
"$response".padLeft( itemNumber, '0' )
And you don't need examineeResponses at all.
One of the bits I struggle with in your question is I don't know what examineeResponses.length() is supposed to do (other than throw an error). Another is I'm not sure that this is what you want to do ;-)
You can't zero pad Strings with String.format in Java or Groovy, you can only zero pad numerics
Try something like this:
def formattedString = "blahblah.com?param=${param}&hash=${hash}"

Resources