I came across the following syntax in a GTM script and am not quite sure how it's supposed to work:
if(!!{{var1}} && !!{{var2}}){
// . . . other code here
}
Now, I can tell that the {{}} syntax is used to capture variable values, but I can't find any reference to the !! operator (if there is such a thing).
Does it represent something in GTM, or is it just sloppy programming and these !! can be removed? I should mention that there are many more if statements in this script and they all look sane. This is the only one that has these !!. Any ideas?
This is not GTM script specific, it's a standard JavaScript practice to coerce objects to boolean. In JavaScript there are falsey values like null or undefined, etc. (list here), these will be false after using !! (bang bang), otherwise, true.
Note that this is not a special operand, just ! (NOT) used twice to force the type to be boolean.
Here is a good article that explains it very well: https://medium.com/#edplatomail/js-double-bang-or-the-not-operator-part-40e55d089bf0
To answer your question, it is not sloppy programming, and should not be removed.
Related
One of the useful features of ess-mode (Emacs speaks statistics) is to automatically replace the underscore _ with the assignment operator <-. Lately, I have been using a lot of pipes (written as %>%) and it would be great to not have to type three characters for each pipe.
Is it possible to define a custom key binding for the pipe, similar to the one converting _ into ->?
The simplest solution is to just bind a key to insert a string:
(define-key ess-mode-map (kbd "|") "%>%")
You can still insert | with C-q |. I'm not sure about the map's name; you'll almost certainly want to limit the key binding to ess-mode.
Check out yasnippet. You can use it to define something like "if this sequence of characters is followed by this key (which you can define to whatever you like), then replace them with this other sequence of characters and leave the cursor in this place". There's more to yasnippet than this, but there's plenty of documentation online and even already made recipes similar to the example I gave above that you can try, like yasnippet-ess-mode, for example.
Alternatively, you can also try abbrev-mode and see if that works for you.
I, for one, like yasnippet better, since you can also specify where to leave the cursor after the expansion, but abbrev-mode seems to be easier to set up. As always in Emacs world, try multiple solutions, don't settle for the first one you put your hands on. What works best for others might not work for you, and vice-versa.
I wanted to answer a question regarding plotmath but I failed to get my desired substitute output.
My desired output:paste("Hi", paste(italic(yes),"why not?"))
and what I get: paste("Hi", "paste(italic(yes),\"why not?\")")
text<-'paste(italic(yes),"why not?")'
text
[1] "paste(italic(yes),\"why not?\")"
noqoute_text<-noquote(text)
noqoute_text
[1] paste(italic(yes),"why not?")
sub<-substitute(paste("Hi",noqoute_text),
env=list(noqoute_text=noqoute_text))
sub
paste("Hi", "paste(italic(yes),\"why not?\")")
You're using the wrong function, use parse instead of noquote :
text<-'paste(italic(yes),"why not?")'
noquote_text <- parse(text=text)[[1]]
sub<- substitute(paste("Hi",noquote_text),env=list(noquote_text= noquote_text))
# paste("Hi", paste(italic(yes), "why not?"))
noquote just applies a class to an object of type character, with a specific print method not to show the quotes.
str(noquote("a"))
Class 'noquote' chr "a"
unclass(noquote("a"))
[1] "a"
Would you please elaborate on your answer?
In R you ought to be careful about the difference between what's in an object, and what is printed.
What noquote does is :
add "noquote" to the class attribute of the object
That's it
The code is :
function (obj)
{
if (!inherits(obj, "noquote"))
class(obj) <- c(attr(obj, "class"), "noquote")
obj
}
Then when you print it, the methods print.noquote :
Removes the class "noquote" from the object if it's there
calls print with the argument quote = FALSE
that's it
You can actually call print.noquote on a string too :
print.noquote("a")
[1] a
It does print in a similar fashion as quote(a) or substitute(a) would but it's a totally different beast.
In the code you tried, you've been substituting a string instead of a call.
For solving the question I think Moody_Mudskipperss answer works fine, but as you asked for some elaboration...
You need to be careful about different ways similar-looking things are actually stored in R, which means they behave differently.
Especially with the way plotmath handles labels, as they try to emulate the way character-strings are normally handled, but then applies its own rules. The 3 things you are mixing I think:
character() is the most familiar: just a string. Printing can be confusing when quotes etc. are escaped. The function noquote basically tells R to mark it's argument, so that quotes are not escaped.
calls are "unevaluated function-calls": it's an instruction as to what R should do, but it's not yet executed. Any errors in this call don't come up yet, and you can inspect it.
Note that a call does not have its own evironment given with it, which means a call can give different results if evaluated e.g. from within a function.
Expressions are like calls, but applied more generally, i.e. not always a function that needs to be executed. An expression can be a variable-name, but also a simple value such as "why not?". Also, expressions can consist of multiple units, like you would have with {
Different functions can convert between these classes, but sometimes functions (such as paste!) also convert unexpectedly:
noquote does not do that much useful, as Moody_Mudskipper already pointed out: it only changes the printing. But the object basically remains a character
substitute not only substitutes variables, but also converts its first argument into (most often) a call. Here, the print bites you, for when printing a call, there is no provision for special classes of its members. Try it: sub[[3]] from the question gives[1] paste(italic(yes),"why not?")
without any backslashes! Only when printing the full call the noquote-part is lost.
parse is used to transform a character to an expression. Nothing is evaluated yet, but some structure is introduced, so that you could manipulate the expression.
paste is often behaving annoyingly (although as documented), as it can only paste together character-strings. Therefore, if you feed it anything but a character, it firs calls as.character. So if you give it a call, you just get a text-line again. So in your question, even if you'd use parse, as soon as you start pasting thing together, you get the quotes again.
Finally, your problem is harder because it's using plotmaths internal logic.
That means that as soon as you try to evaluate your text, you'll probably get an error "could not find function italic" (or a more confusing error if there is a function italic defined elsewhere). When providing it in plotmath, it works because the call is only evaluated by plotmath, which will give it a nice environment, where italic works as expected.
This all means you need to treat it all as an expression or call. As long as evaluation cannot be done (as long as it's you that handles the expression, instead of plotmath) it all needs to remain an expression or call. Giving substitute a call works, but you can also emulate more closely what happens in R, with
call('paste', 'Hi', parse(text=text)[[1]])
I have a problem to extract function arguments in R.
x="theme(legend.position='bottom',
legend.margin=(t=0,r=0,b=0,l=0,unit='mm'),
legend.background=element_rect(fill='red',size=rel(1.5)),
panel.background=element_rect(fill='red'),
legend.position='bottom')"
What I want is:
[1]legend.position='bottom'
[2]legend.margin=(t=0,r=0,b=0,l=0,unit='mm')
[3]legend.background=element_rect(fill='red',size=rel(1.5))
[4]panel.background=element_rect(fill='red')
[5]legend.position='bottom'
I tried several regular expressions without success including followings:
strsplit(x,",(?![^()]*\\))",perl=TRUE)
Please help me!
I think the best answer here might be to not attempt to use a regex to parse your function call. As the name implies, regular expressions require regular language. Your function call is not regular, because it has nested parentheses. I currently see a max nested depth of two, but who knows if that could get deeper at some point.
I would recommend writing a simple parser instead. You can use a stack here, to keep track of parentheses. And you would only split a parameter off if all parentheses were closed, implying that you are not in the middle of a parameter, excepting possibly the very first one.
Arf, I'm really sorry but i have to go work, i will continue later but for now i just let my way to solve it partially : theme\(([a-z.]*=['a-z]*)|([a-z._]*=[a-z0-9=,'_.()]*)*\,\)?
It misses only the last part..
Here the regex101 page : https://regex101.com/r/BZpcW0/2
See you later.
Thank you for all your advice. I have parsed the sentences and get the arguments as list. Here is my solution.
x<-"theme(legend.margin=margin(t=0,r=0,b=0,l=0,unit='mm'),
legend.background=element_rect(fill='red',size=rel(1.5)),
panel.background=element_rect(fill='red'),
legend.position='bottom')"
extractArgs=function(x){
result<-tryCatch(eval(parse(text=x)),error=function(e) return("error"))
if("character" %in% class(result)){
args=character(0)
} else {
if(length(names(result)>0)){
pos=unlist(str_locate_all(x,names(result)))
pos=c(sort(pos[seq(1,length(pos),by=2)]),nchar(x)+1)
args=c()
for(i in 1:(length(pos)-1)){
args=c(args,substring(x,pos[i],lead(pos)[i]-2))
}
} else{
args=character(0)
}
}
args
}
I am interested it writing a few operators. Many characters are reserved and cannot be used a or b for example while others are currently used and I would not like them overwritten +,-,>, and < for example. There are others which are unavailable for less clear reasons such as $ or #.
I would like a list of characters that can be used as user written operators.
Thanks for your help,
Francis
Both "?" and "!" can be overloaded. I'm not going to reproduce the source code here, but take a look at the sos package and at the cgwtools::splatnd function for info on how to write your own unary (single-argument) operators.
I believe there's a tutorial on how to write %foo% binary operators but I forget where I saw it :-(
I found the answer to this, but it's a bit of a gotcha so I wanted to share it here.
I have a regular expression that validates passwords. They should be 7 to 60 characters with at least one numeric and one alpha character. Pretty standard. I used positive lookaheads (the (?= operator) to implement it:
(?=^.{7,60}$)(?=.*[0-9].*)(?=.*[a-zA-Z].*)
I checked this expression in my unit tests using Regex.IsMatch(), and it worked fine. However, when I use it in a RegularExpressionValidator, it always fails. Why?
It's strange that I've never run into this before, but it turns out that the RegularExpressionValidator doesn't use Regex.IsMatch or JavaScript's Regex.test() -- it checks for a capturing match that exactly equals the full tested value. Here's the relevant JS code:
var rx = new RegExp(val.validationexpression);
var matches = rx.exec(value);
return (matches != null && value == matches[0]);
So if the expression is all lookaheads (which match positions, not the actual text), it will fail. This is clearer with the example of an expression that only partially matches, e.g. with \d{5}, the value "123456" would fail. It's not just that it adds "^$" around your expression and does an IsMatch. Your expression actually has to capture.
The fix in my case is this expression:
(?=^.{7,60}$)(?=.*[0-9].*).*[a-zA-Z].*
Have you tried
(?=^.{7,60}$)(?=.*[0-9].*)(?=.*[a-zA-Z].*).+
// ^^
? The regex should need something to consume.