I want to set a variable inside Knowledge Module's Task, with target technology set to Java BeanShell. The value represents mapping EXPRESSIONs, where source table is inside MSSQL database. Column names are surrounded by double quotes, that causes a problem with templating.
Column expression is:
source_tab."Entry Number"
Task (Java BeanShell)
<$
String SEL_COLS = "<%=odiRef.getColList(0, "", "[EXPRESSION]\t[ALIAS_SEP] [CX_COL_NAME]", ",\n\t", "", "")%>";
$>
This variable assignment fails, because " in source_tab."Entry Number" is not escaped - code does not compile.
odiRef.getQuotedString does not solve the problem...
odiRef.getQuotedString could help if generated code is executed as a final code in JBS technology. When we use it in the following way (in ?-, $- or #-substitution):
<$
String SEL_COLS = <%=odiRef.getQuotedString(odiRef.getColList(0, "", "[EXPRESSION]\t[ALIAS_SEP] [CX_COL_NAME]", ",\n\t", "", ""))%>;
$>
then result fails like this:
... Caused by: org.apache.bsf.BSFException: BeanShell script error:
Parse error at line 3, column 37. Encountered: Entry BSF info: ....
... 11 more
Text: <$
String SEL_COLS = "SOURCE_TAB.\"Entry Number\" ENTRY_NUMBER";
$>.
This looks good but does not work. It could work as final code (I mean result of all substitutions) in JBS Technology. Unfortunately any substitutions eats backslashes.
Ok, if standard odiRef-functtion does not work, lets write our own:
<%
String getQuotedStringCustomized(String s){
return '"'+s.replaceAll('"'.toString(),'"'+"+'"+'"'+"'+"+'"')+'"';
}
%>
-- other code........
<$
String SEL_COLS = <%=getQuotedStringCustomized(odiRef.getColList(0, "", "[EXPRESSION]\t[ALIAS_SEP] [CX_COL_NAME]", ",\n\t", "", ""))%>;
$>
Only the way to put " into a Java literal within the JBS Substitution is contatenation with Char literal '"' or using '"'.toString() expression if it is impossible to use Char type.
FINALLY:
In final JBS code you may use \", but within substitutions only +'"'+.
Related
I stumbled over this problem using the following simplified example:
line = searchstring.dup
line.gsub!(Regexp.escape(searchstring)) { '' }
My understanding was, that for every String stored in searchstring, the gsub! would cause that line is afterwards empty. Indeed, this is the case for many strings, but not for this case:
searchstring = "D "
line = searchstring.dup
line.gsub!(Regexp.escape(searchstring)) { '' }
p line
It turns out, that line is printed as "D " afterwards, i.e. no replacement had been performed.
This happens to any searchstring containing a space. Indeed, if I do a
p(Regexp.escape(searchstring))
for my example, I see "D\\ " being printed, while I would expect to get "D " instead. Is this a bug in the Ruby core library, or did I misuse the escape function?
Some background: In my concrete application, where this simplified example is derived from, I just want to do a literal string replacement inside a long string, in the following way:
REPLACEMENTS.each do
|from, to|
line.chomp!
line.gsub!(Regexp.escape(from)) { to }
end
. I'm using Regexp.escape just as a safety measure in the case that the string being replaced contains some regex metacharacter.
I'm using the Cygwin port of MRI Ruby 2.6.4.
line.gsub!(Regexp.escape(searchstring)) { '' }
My understanding was, that for every String stored in searchstring, the gsub! would cause that line is afterwards empty.
Your understanding is incorrect. The guarantee in the docs is
For any string, Regexp.new(Regexp.escape(str))=~str will be true.
This does hold for your example
Regexp.new(Regexp.escape("D "))=~"D " # => 0
therefore this is what your code should look like
line.gsub!(Regexp.new(Regexp.escape(searchstring))) { '' }
As for why this is the case, there used to be a bug where Regex.escape would incorrectly handle space characters:
# in Ruby 1.8.4
Regex.escape("D ") # => "D\\s"
My guess is they tried to keep the fix as simple as possible by replacing 's' with ' '. Technically this does add an unnecessary escape character but, again, that does not break the intended use of the method.
This happens to any searchstring containing a space. Indeed, if I do a
p(Regexp.escape(searchstring))
for my example, I see "D\\ " being printed, while I would expect to get "D " instead. Is this a bug in the Ruby core library, or did I misuse the escape function?
This looks to be a bug. In my opinion, whitespace is not a Regexp meta character, there is no need to escape it.
Some background: In my concrete application, where this simplified example is derived from, I just want to do a literal string replacement inside a long string […]
If you want to do literal string replacement, then don't use a Regexp. Just use a literal string:
line.gsub!(from, to)
I have a script in bash that calls a TCL script for each element on my network which performs some actions based on the type of the element. This is part of the code that checks whether or not the hostname contains a specific pattern(e.g. *CGN01) and then gives the appropriate command to that machine.
if {[string match "{*CGN01}" $hostname] || $hostname == "AthMet1BG01"} {
expect {
"*#" {send "admin show inventory\r"; send "exit\r"; exp_continue}
eof
}
}
With the code i quoted above i get no error BUT when the hostname is "PhiMSC1CGN01" then the code inside the if is not executed which means that the expression is not correct.
I have tried everything (use of "()" or "{}" or"[]" inside the if) but when i dont put "" on the pattern i get an error like:
invalid bareword "string"
in expression "(string match {*DR0* *1TS0* *...";
should be "$string" or "{string}" or "string(...)" or ...
(parsing expression "(string match {*DR0* *...")
invoked from within
"if {$hostname == "AthMar1BG03" || [string match *CGN01 $hostname]...
or this:
expected boolean value but got "[string match -nocase "*CGN01" $hostname]==0"
while executing
"if {$hostname == "AthMar1BG03" || {[string match -nocase "*CGN01" $hostname]==0}...
when i tried to use ==0 or ==1 on the expression.
My TCL-Version is 8.3 and i cant update it because the machine has no internet connecticity :(
Please help me i am trying to fix this for over a month...
If you want to match a string that is either exactly AthMet1BG01 or any string that ends with CGN01, you should use
if {[string match *CGN01 $hostname] || $hostname == "AthMet1BG01"} {
(For Tcl 8.5 or later, use eq instead of ==.)
Some comments on your attempts:
(The notes about the expression language used by if go for expr and while as well. It is fully described in the documentation for expr.)
To invoke a command inside the condition and substitute its result, it needs to be enclosed in brackets ([ ]). Parentheses (( )) can be used to set the priority of subexpressions within the condition, but don't indicate a command substitution.
Normally, inside the condition strings need to be enclosed in double quotes or braces ({ }). This is because the expression language that is used to express the condition needs to distinguish between e.g. numbers and strings, which Tcl in general doesn't. Inside a command substitution within a condition, you don't need to use quotes or braces, as long as there are no characters in the string that you need to quote.
The string {abc} contains the characters abc. The string "{abc}" contains the characters {abc}, because the double quotes make the braces normal characters (the reverse also holds). [string match "{*bar}" $str] matches the string {foobar} (with the braces as part of the text), but not foobar.
If you put braces around a command substitution, {[incr foo]}, it becomes just the string [incr foo], i.e. the command isn't invoked and no substitution is made. If you use {[incr foo]==1} you get the string [incr foo]==1. The correct way to write this within an expression is [incr foo]==1, with optional whitespace around the ==.
All this is kind of hard to grok, but when you have it is really easy to use. Tcl is stubborn as a mule about interpreting strings, but carries heavy loads if you treat her right.
ETA an alternate matcher (see comments)
You can write your own alternate string matcher:
proc altmatch {patterns string} {
foreach pattern $patterns {
if {[string match $pattern $string]} {
return 1
}
}
return 0
}
If any of the patterns match, you get 1; if none of the patterns match, you get 0.
% altmatch {*bar f?o} foobar
1
% altmatch {*bar f?o} fao
1
% altmatch {*bar f?o} foa
0
For those who have a modern Tcl version, you can actually add it to the string ensemble so it works like other string commands. Put it in the right namespace:
proc ::tcl::string::altmatch {patterns string} {
... as before ...
and install it like this:
% set map [namespace ensemble configure string -map]
% dict set map altmatch ::tcl::string::altmatch
% namespace ensemble configure string -map $map
Documentation:
expr,
string,
Summary of Tcl language syntax
This command:
if {[string match "{*CGN01}" $hostname] || $hostname == "AthMet1BG01"} {
is syntactically valid but I really don't think that you want to use that pattern with string match. I'd guess that you really want:
if {[string match "*CGN01" $hostname] || $hostname == "AthMet1BG01"} {
The {braces} inside that pattern are not actually meaningful (string match only does a subset of the full capabilities of a glob match) so with your erroneous pattern you're actually trying to match a { at the start of $hostname, any number of characters, and then CGN01} at the end of $hostname. With the literal braces. Simply removing the braces lets PhiMSC1CGN01 match.
Following is my code:
md5 = Digest::MD5.new
md5 << "!##$"
Then comes the error:
SyntaxError: (irb):46: unterminated string meets end of file
What is wrong? And how can I calculate the md5 hash of the string "!##$"?
The hash # sign in double quoted strings is used for variable and expression substitution. In this case, you are substituting the value of the global variable $" into the string, but you are not closing the string. The syntactically correct way of expressing that would be
"!##$"" # Note the extra closing quotes
However, it seems that you actually don't want to do variable substitution anyway, in which case you should always use single quoted strings:
'!##$'
Seems like you need to quote #:
> puts "!#\#$"
!##$
Your problem is the string you got is in a double apostrophe (") - so it is interpreted. And you have a hash (#) inside, so it is trying to do expression substitution. Put the string in a single apostrophe:
md5 << '!##$'
So far I only see stuff like '<' ,but never see 'abc' nor "abc" in a yacc file.
a:
b '<' c;
Are the later two valid at all?
'abc' = is valid character since whenever you specify char like this compiler/preprocessor
simply remove last character , sometimes you would get "character constants must be one or two character long" compile time error in ANSI C.If it is not given by your compiler then
it has removed last 'c' from 'abc' should be assumed.
so
char ch='abc' ; // is actually equi. to ch = 'ab'
but while binding it will only use ch='a' ,that's why 'abc' is syntaxically correct but symantically wrong characher.(I wrote C coz. we use c89 tool i.e. POSIX C for compiling yacc and lex inputs)
Again yylex() works on characters as basic functional unit and not string (anything inside double quotes). So "abc" is not valid character not even character to match with yylex()'s
input.
(yylex() accepts string of token
exam. "10+20"
having grammer [[:DIGIT:]]+ [-+*/%] [[:DIGIT:]]+
and having tokens 1,0,+,2,0
The tokens lex can identify by default w/o specifying grammer are
10 as number
+ as char and
20 as number again
so it will match with grammer specified before )
you can also specify string in rules section for matching with , like
^["I am"] means match with any input line starting with "I am"
"I am" match with only input having string as "I am" only , It wont match with "I am Swapnil # vikas.ghode#gmail.com"
Consider the following string which is a C fragment in a file:
strcat(errbuf,errbuftemp);
I want to replace errbuf (but not errbuftemp) with the prefix G-> plus errbuf. To do that successfully, I check the character after and the character before errbuf to see if it's in a list of approved characters and then I perform the replace.
I created the following Ruby file:
line = " strcat(errbuf,errbuftemp);"
item = "errbuf"
puts line.gsub(/([ \t\n\r(),\[\]]{1})#{item}([ \t\n\r(),\[\]]{1})/, "#{$1}G\->#{item}#{$2}")
Expected result:
strcat(G->errbuf,errbuftemp);
Actual result
strcatG->errbuferrbuftemp);
Basically, the matched characters before and after errbuf are not reinserted back with the replace expression.
Anyone can point out what I'm doing wrong?
Because you must use syntax gsub(/.../){"...#{$1}...#{$2}..."} or gsub(/.../,'...\1...\2...').
Here was the same problem: werid, same expression yield different value when excuting two times in irb
The problem is that the variable $1 is interpolated into the argument string before gsub is run, meaning that the previous value of $1 is what the symbol gets replaced with. You can replace the second argument with '\1 ?' to get the intended effect. (Chuck)
I think part of the problem is the use of gsub() instead of sub().
Here's two alternates:
str = 'strcat(errbuf,errbuftemp);'
str.sub(/\w+,/) { |s| 'G->' + s } # => "strcat(G->errbuf,errbuftemp);"
str.sub(/\((\w+)\b/, '(G->\1') # => "strcat(G->errbuf,errbuftemp);"