Understanding string.gsub in Lua - string

I'm trying to print a gsub string (in Lua) to stdout here how my code look like.
print('string.gsub(\'VEECTORY\',\'EE\',\'I\') =>', string.gsub('VEECTORY','EE','I'))
Everytime I run this, although I get the desired result but I see 1 appearing in the output.
So, the output look like this.
string.gsub('VEECTORY','EE','I') => VICTORY 1
I'm unable to understand what does that 1 stand for but if I used a variable I don't see that 1 anymore.
local replace_string = string.gsub('VEECTORY','EE','I')
print('string.gsub(\'VEECTORY\',\'EE\',\'I\') =>',replace_string)
I get output as
string.gsub('VEECTORY','EE','I') => VICTORY
I also notice that when I run the above code in Lua console
i.e this code
local replace_string = string.gsub('VEECTORY','EE','I')
print('string.gsub(\'VEECTORY\',\'EE\',\'I\') =>',replace_string)
I get the output as nil
What am I missing ?

string.gsub has two return values. The first is result string, while the second is the total number of matches that occurred.
In your example:
string.gsub('VEECTORY','EE','I')
The second return value is 1 because the substitution happened once.
When you assign the result as:
local replace_string = string.gsub('VEECTORY','EE','I')
The first return value is assigned to replace_string, while the second return value is discarded.
You can get the second return value explicitly by:
local replace_string, num = string.gsub('VEECTORY','EE','I')
Finally, in interactive mode, each line is a chunk by itself, so the local variables are out of scope in the next line, therefore you saw replace_string becomes nil. If you use global variables:
replace_string = string.gsub('VEECTORY','EE','I')
print('string.gsub(\'VEECTORY\',\'EE\',\'I\') =>',replace_string)
The output will be as expected in interactive mode as well.

Related

Why does this recursive addition return none

This is a weird one print return 9 and then it prints 1 , also i checked debugger in pycharm and the (stuff) keeps counting down for some reason
def repeater(stuff):
if stuff != 9:
stuff += 1
print(stuff)
repeater(stuff)
return stuff
print(repeater(0))
When you call repeater(stuff), you're not passing the variable stuff, you're passing a copy of the variable stuff. When you say stuff += 1, you're not modifying the stuff you called the function with, you're modifying a copy of it. That change isn't reflected in the original when you exit the function.
Then, when the function exits, you don't do anything with the returned value of stuff - which is, again, copied out of the function in reverse. Python does let you call the function without using its return value, but it looks like your intent here is to apply the returned value of repeater(stuff) to stuff.
To accomplish that, simply change the line
repeater(stuff)
to
stuff = repeater(stuff)
The reason for that additional 1 that is coming in the end is that repeater(stuff) is returning the value of stuff which is being received by your print statement i.e. print(repeater(0)). When all the recursive calls return back, none of the values are stored/used but the very first call that was made by print(repeater(0)) obtains a value of 1 because repeater(stuff) returns the value of stuff which would be 1 after stuff += 1 during the first call.
You can read more about how recursion works for more clarity.

“P6opaque, Str” vs simple “Str” types in Perl 6

This is a follow-up to my previous question.
I am finally able to reproduce the error here:
my #recentList = prompt("Get recentList: e.g. 1 2 3: ").words || (2,4,6);
say "the list is: ", #recentList;
for #recentList -> $x {
say "one element is: ", $x;
say "element type is: ", $x.WHAT;
say "test (1,2,3).tail(\"2\") : ", (1,2,3).tail("2");
say ( (10.rand.Int xx 10) xx 15 ).map: { #($_.tail($x)); };
}
And the results are ok as long as I use the default list by just hitting return at the prompt and not entering anything. But if I enter a number, it gives this error:
Get recentList: e.g. 1 2 3: 2
the list is: [2]
one element is: 2
element type is: (Str)
test (1,2,3).tail("2") : (2 3)
This type cannot unbox to a native integer: P6opaque, Str
in block at intType.p6 line 9
in block <unit> at intType.p6 line 5
If tail("2") works, why does tail($x) fail? Also, in my original code, tail($x.Int) wouldn't correct the problem, but it did here.
This is at best a nanswer. It is a thus-far failed attempt to figure out this problem. I may have just wandered off into the weeds. But I'll publish what I have. If nothing else, maybe it can serve as a reminder that the first three steps below are sensible ones; thereafter I'm gambling on my ability to work my way forward by spelunking source code when I would probably make much faster and more reliable progress by directly debugging the compiler as discussed in the third step.
OK, the first step was an MRE. What you've provided was an E that was fully R and sufficiently M. :)
Step #2 was increasing the M (golfing). I got it down to:
Any.tail('0'); # OK
Any.tail('1'); # BOOM
Note that it can be actual values:
1.tail('1'); # BOOM
(1..2).tail('1'); # BOOM
But some values work:
(1,2).tail('1'); # OK
Step #3 probably should be to follow the instructions in Playing with the code of Rakudo Perl 6 to track the compiler's execution, eg by sticking says in its source code and recompiling it.
You may also want to try out App::MoarVM::Debug. (I haven't.)
Using these approaches you'll have the power to track with absolute precision what the compiler does for any code you throw at it. I recommend you do this even though I didn't. Maybe you can figure out where I've gone wrong.
In the following I trace this problem by just directly spelunking the Rakudo compiler's source code.
A search for "method tail" in the Rakudo sources yielded 4 matches. For my golf the matching method is a match in core/AnyIterableMethods.pm6.
The tail parameter $n clearly isn't a Callable so the pertinent line that continues our spelunking is Rakudo::Iterator.LastNValues(self.iterator,$n,'tail').
A search for this leads to this method in core/Iterator.pm6.
This in turn calls this .new routine.
These three lines:
nqp::if(
n <= 0, # must be HLL comparison
Rakudo::Iterator.Empty, # negative is just nothing
explain why '0' works. The <= operator coerces its operands to numeric before doing the numeric comparison. So '0' coerces to 0, the condition is True, the result is Rakudo::Iterator.Empty, and the Any.tail('0') yields () and doesn't complain.
The code that immediately follows the above three lines is the else branch of the nqp::if. It closes with nqp::create(self)!SET-SELF(iterator,n,f).
That in turn calls the !SET-SELF routine, which has the line:
($!lastn := nqp::setelems(nqp::list, $!size = size)),
Which attempts to assign size, which in our BOOM case is '1', to $!size. But $!size is declared as:
has int $!size;
Bingo.
Or is it? I don't know if I really have correctly tracked the problem down. I'm only spelunking the code in the github repo, not actually running an instrumented version of the compiler and tracing its execution, as discussed as the sensible step #3 for trying to figure out the problem you've encountered.
Worse, when I'm running a compiler it's an old one whereas the code I'm spelunking is the master...
Why does this work?
(*,*).tail('1') # OK
The code path for this will presumably be this method. The parameter $n isn't a Callable so the code path will run thru the path that uses the $n in the lines:
nqp::unless(
nqp::istype($n,Whatever) || $n == Inf,
$iterator.skip-at-least(nqp::elems($!reified) - $n.Int)
The $n == Inf shouldn't be a problem. The == will coerce its operands to numerics and that should take care of $n being '1'.
The nqp::elems($!reified) - $n.Int shouldn't be a problem either.
The nqp ops doc shows that nqp::elems always returns an int. So this boils down to an int - Int which should work.
Hmm.
A blame of these lines shows that the .Int in the last line was only added 3 months ago.
So, clutching at straws, what happens if one tries:
(my int $foo = 1) - '1' # OK
Nope, that's not the problem.
It seems the trail has grown cold or rather I've wandered off the actual execution path.
I'll publish what I've got. Maybe someone else can pick it up from here or I'll have another go in a day or three...

Coffeescript - how do I check string equality when passing string through a splat?

I'm having trouble checking whether two strings are equal when one of them was passed through a splat argument. Because coffeescript uses strict comparisons, and because it makes a copy of the arguments when they go through a splat, I can't get the strings to compare properly without resorting to backticks. Is there a better way? Here's a minimal piece of code that demonstrates the problem:
check=(arg) ->
if arg == 'foo' then "'#{arg}'=='foo'" else "'#{arg}'!='foo'"
emit=(args...) ->
check(args)
console.log(emit('foo'))
console.log(check('foo'))
The output from this will be as follows:
> coffee mincase.coffee
'foo'!='foo'
'foo'=='foo'
EDIT:
mu is too short gave me the key, so the revised working code looks like this (everything is the same except emit)
emit=(args...)->
check.apply(null,args)
When you use a splat, the splat puts the splatted arguments into an array. For example:
f = (x...) -> console.log(x instanceof Array)
f(6)
will give you a true in the console. The fine manual isn't so fine in this case, it doesn't exactly spell it out, it assumes that you understand how JavaScript's arguments object works and leaves out the explicit splat puts your arguments into an array part.
So you end up passing an array to check and an array compared with a string using CoffeeScript's == (or JavaScript's ===) will never be true.
If you want emit to check the first argument, then you need to say so:
emit = (args...) -> check(args[0])
Demo: http://jsfiddle.net/ambiguous/TBndM/

Detecting if a variable can be printed in Lua

I've got a variable that could be a number of types - sometimes it's a string, sometimes a number, table or bool. I'm trying to print out the value of the variable each time like this:
print("v: "..v)
with v being my variable. Problem is, when I get a value that can't be concatenated I get this error:
myscript.lua:79: attempt to concatenate a table value
I've tried changing it to this in case it manages to detect whether or not the variable can be printed:
print("v: "..(v or "<can't be printed>"))
but I had the same problem there. Is there some sort of function I can use to determine if a variable can be concatenated to a string, or a better way of printing out variables?
You can provide the values as separate arguments to print:
print("v:", v)
This would print something like
v: table: 006CE900
Not necessarily the most useful, but better than a crash if it's just for debugging purposes.
See here for information on more useful table printing.
tostring(v) works for all possible v values (including nil). So writing your line as:
print( "v: " .. tostring( v ) )
will always work.
Alternatively you could have a look at type( v ) and if its "string" print it, otherwise print something else (if that's what you want).

Convert string to a variable name

I am using R to parse a list of strings in the form:
original_string <- "variable_name=variable_value"
First, I extract the variable name and value from the original string and convert the value to numeric class.
parameter_value <- as.numeric("variable_value")
parameter_name <- "variable_name"
Then, I would like to assign the value to a variable with the same name as the parameter_name string.
variable_name <- parameter_value
What is/are the function(s) for doing this?
assign is what you are looking for.
assign("x", 5)
x
[1] 5
but buyer beware.
See R FAQ 7.21
http://cran.r-project.org/doc/FAQ/R-FAQ.html#How-can-I-turn-a-string-into-a-variable_003f
You can use do.call:
do.call("<-",list(parameter_name, parameter_value))
There is another simple solution found there:
http://www.r-bloggers.com/converting-a-string-to-a-variable-name-on-the-fly-and-vice-versa-in-r/
To convert a string to a variable:
x <- 42
eval(parse(text = "x"))
[1] 42
And the opposite:
x <- 42
deparse(substitute(x))
[1] "x"
The function you are looking for is get():
assign ("abc",5)
get("abc")
Confirming that the memory address is identical:
getabc <- get("abc")
pryr::address(abc) == pryr::address(getabc)
# [1] TRUE
Reference: R FAQ 7.21 How can I turn a string into a variable?
Use x=as.name("string"). You can use then use x to refer to the variable with name string.
I don't know, if it answers your question correctly.
strsplit to parse your input and, as Greg mentioned, assign to assign the variables.
original_string <- c("x=123", "y=456")
pairs <- strsplit(original_string, "=")
lapply(pairs, function(x) assign(x[1], as.numeric(x[2]), envir = globalenv()))
ls()
assign is good, but I have not found a function for referring back to the variable you've created in an automated script. (as.name seems to work the opposite way). More experienced coders will doubtless have a better solution, but this solution works and is slightly humorous perhaps, in that it gets R to write code for itself to execute.
Say I have just assigned value 5 to x (var.name <- "x"; assign(var.name, 5)) and I want to change the value to 6. If I am writing a script and don't know in advance what the variable name (var.name) will be (which seems to be the point of the assign function), I can't simply put x <- 6 because var.name might have been "y". So I do:
var.name <- "x"
#some other code...
assign(var.name, 5)
#some more code...
#write a script file (1 line in this case) that works with whatever variable name
write(paste0(var.name, " <- 6"), "tmp.R")
#source that script file
source("tmp.R")
#remove the script file for tidiness
file.remove("tmp.R")
x will be changed to 6, and if the variable name was anything other than "x", that variable will similarly have been changed to 6.
I was working with this a few days ago, and noticed that sometimes you will need to use the get() function to print the results of your variable.
ie :
varnames = c('jan', 'feb', 'march')
file_names = list_files('path to multiple csv files saved on drive')
assign(varnames[1], read.csv(file_names[1]) # This will assign the variable
From there, if you try to print the variable varnames[1], it returns 'jan'.
To work around this, you need to do
print(get(varnames[1]))
If you want to convert string to variable inside body of function, but you want to have variable global:
test <- function() {
do.call("<<-",list("vartest","xxx"))
}
test()
vartest
[1] "xxx"
Maybe I didn't understand your problem right, because of the simplicity of your example. To my understanding, you have a series of instructions stored in character vectors, and those instructions are very close to being properly formatted, except that you'd like to cast the right member to numeric.
If my understanding is right, I would like to propose a slightly different approach, that does not rely on splitting your original string, but directly evaluates your instruction (with a little improvement).
original_string <- "variable_name=\"10\"" # Your original instruction, but with an actual numeric on the right, stored as character.
library(magrittr) # Or library(tidyverse), but it seems a bit overkilled if the point is just to import pipe-stream operator
eval(parse(text=paste(eval(original_string), "%>% as.numeric")))
print(variable_name)
#[1] 10
Basically, what we are doing is that we 'improve' your instruction variable_name="10" so that it becomes variable_name="10" %>% as.numeric, which is an equivalent of variable_name=as.numeric("10") with magrittr pipe-stream syntax. Then we evaluate this expression within current environment.
Hope that helps someone who'd wander around here 8 years later ;-)
Other than assign, one other way to assign value to string named object is to access .GlobalEnv directly.
# Equivalent
assign('abc',3)
.GlobalEnv$'abc' = 3
Accessing .GlobalEnv gives some flexibility, and my use case was assigning values to a string-named list. For example,
.GlobalEnv$'x' = list()
.GlobalEnv$'x'[[2]] = 5 # works
var = 'x'
.GlobalEnv[[glue::glue('{var}')]][[2]] = 5 # programmatic names from glue()

Resources