So this is a robust problem. I have a function which accepts 2 args (string_name, macros). Here it is so I can further explain.
function ParseStrings(string_name, macros)
return my_table[string_name]
-- All it does it returns the string_name's value
end
The problem is that the second arg is a table, and if it's a table then in the string there are going to be various parts that have the format "String stuff $MACRO_KEY; more string text" and the content between the $ and ; is the key to look up in the macro table sent with it. Now anytime a value like that appears in the string there will always be a second arg that's a table, so no problems their. I need to be able to count up the number of instances of macros in a string and then replace each macro component with it's respective macros' table value. So here's how the func is called in this instance...
local my_table = {
my_string = "My string content $MACRO_COMPONENT; more string stuff $MACRO_COMPONENT_SUB;$MACRO_COMPONENT_ALT;"
}
local macro = {
MACRO_COMPONENT = "F",
MACRO_COMPONENT_SUB = "Random Text",
MACRO_COMPONENT_ALT = "14598"
}
function ParseStrings(string_name, macros)
return my_table[string_name]
-- All it does it returns the string_name's value
end
ParseStrings("my_string", macro)
So I am thinking:
string.gsub(my_table[my_string]:match("%b$;"):sub(2,my_table[my_string]:match("%b$;"):len() - 1)
but this is a long and overtly complex answer (AFAIK) and from my tests it only does 1 replacement (because the pattern is only found once) and that's doesn't work well if there are multiple instances in the string. So ideas?
Related
First time posting here. I'm an experienced coding, but it's been a long time since I've done any, and I'm starting back up with App Script, a new language for me. I'm trying to do some basic stuff with text found within cells in a Google sheets. I've gotten it to work well enough, but I think my code can be simplified and improved if I learn a little bit more about working with text strings in App Script.
This is a very simplified version of my function. My real function finds the page numbers given in a citation in one cell, and puts just those page numbers in another cell. For the purposes of this question, I've simplified it to retrieve the text from the current cell, remove the first blank space in the text, count the numbers at the beginning of the text, and then write just those numbers into the current cell. It does what it is supposed to do, and what I need it to do, but I have so many questions! Thank you!!
function myFunction() {
var spreadsheet = SpreadsheetApp.getActive(); var
currentCell = spreadsheet.getCurrentCell().activate();
var style = SpreadsheetApp.newTextStyle().setForegroundColor('#000000').build();
var textString = currentCell.getRichTextValue().getText();
var count = 0;
var char = textString.substring(count,count+1);
textString = textString.replace(" ","");
while(char<10)
{
count = count+1;
char = textString.substring(count,count+1);
}
var numbers = textString.substring(0,count);
currentCell.setRichTextValue(SpreadsheetApp.newRichTextValue().setText(numbers)
.setTextStyle(1, count, style).build());
};
In retrieving my textString, is there a way to do it without using "getRichTextValue()"?
In writing the new text (numbers), is there a way to do that without using "setRichTextValue()"? And to do it without specifying the style?
In my while loop, I use char<10. This works, but I'm not sure why. char is a one character string, right? The character is a number, but I am thinking I shouldn't be able to compare with a number because it's a string? Also, it actually lets blank spaces through as well, so I know something is wrong. What can I do instead?
How can I get the replace function to remove ALL the blank spaces in my textString?
Here is a modified version of your script using Regex.
The reason your code char<10 works is it is comparing the ASCII value of the character with A being 10 and 0 to 9 being ASCII value 0 to 9.
function myFunction() {
var spreadsheet = SpreadsheetApp.getActive();
var currentCell = spreadsheet.getCurrentCell(); // returns a range, no need to activate
var textString = currentCell.getValue();
// use reges to remove all blank spaced
textString = textString.replace(/\s/g,"");
// use regex to get the first string of digits
// match returns an array so we need the first element of the array
var numbers = textString.match(/\d+/)[0];
currentCell.setValue(numbers)
}
Reference
Range.getValue()
Range.setValue()
Regex tester
I have this list:
service_name_status=[a-service=INSTALL, b-service=UPGRADE, C-service=UPGRADE, D-service=INSTALL]
And I need to iterate through this list so the first element will be the value of a parameter called "SERVICE_NAME" and the second element will be the value of a parameter called "HELM_COMMAND",
after asserting those values to the parameters I will run my command that uses those parameters and then continue the next items on the list which should replace the values of the parameters with items 3 and 4 and so on.
So what I am looking for is something like that:
def service_name_status=[a-service=INSTALL, b-service=UPGRADE, C-service=UPGRADE, D-service=INSTALL]
def SERVICE_NAME
def HELM_COMMAND
for(x in service_name_status){
SERVICE_NAME=x(0,2,4,6,8...)
HELM_COMMAND=x(1,3,5,7,9...)
println SERVICE_NAME=$SERVICE_NAME
println HELM_COMMAND=$HELM_COMMAND
}
the output should be:
SERVICE_NAME=a-service
HELM_COMMAND=INSTALL
SERVICE_NAME=b-service
HELM_COMMAND=UPGRADE
SERVICE_NAME=c-service
HELM_COMMAND=UPGRADE
SERVICE_NAME=d-service
HELM_COMMAND=INSTALL
and so on...
I couldn't find anything that takes any other element in groovy, any help will be appreciated.
The collection you want is a Map, not a List.
Take note of the quotes in the map, the values are strings so you need the quotes or it won't work. You may have to change that at the source where your data comes from.
I kept your all caps variable names so you will feel at home, but they are not the convention.
Note the list iteration with .each(key, value)
This will work:
Map service_name_status = ['a-service':'INSTALL', 'b-service':'UPGRADE', 'C-service':'UPGRADE', 'D-service':'INSTALL']
service_name_status.each {SERVICE_NAME, HELM_COMMAND ->
println "SERVICE_NAME=${SERVICE_NAME}"
println "HELM_COMMAND=${HELM_COMMAND}"
}
EDIT:
The following can be used to convert that to a map. Be careful, the replaceAll part is fragile and depends on the data to always look the same.
//assuming you can have it in a string like this
String st = "[a-service=INSTALL, b-service=UPGRADE, C-service=UPGRADE, D-service=INSTALL]"
//this part is dependent on format
String mpStr = st.replaceAll(/\[/, "['")
.replaceAll(/=/, "':'")
.replaceAll(/]/, "']")
.replaceAll(/, /, "', '")
println mpStr
//convert the properly formatted string to a map
Map mp = evaluate(mpStr)
assert mp instanceof java.util.LinkedHashMap
So let's say I have a string called Hi there.
I am currently using
m:match("^(%S+)")
to get just Hi from the string, now all I need to do is just get "there" from the string but I have no idea how.
Checkout this page: http://lua-users.org/wiki/SplitJoin
There are numerous ways to split words in a string on whitespace.
This one seems like it might be a good fit for your problem:
function justWords(str)
local t = {} -- create an empty table
-- create a function to insert a word into the table
local function helper(word) table.insert(t, word) return "" end
-- grab each word in the string and pass it to `helper`
if not str:gsub("%w+", helper):find"%S" then return t end
end
table = justWords(example)
table[1] -- hi
table[2] -- there
table[3] -- nil
I am new to lua and i am trying to extract the value form the right side of a splited string. I have this:
local t ={}
local data = ("ret=OK,type=aircon,reg=eu,dst=1,ver=2_2_5,pow=1,err=0,location=0,name=,icon=0,method=home only,port=30050,id=,pw=,lpw_flag=0,adp_kind=2,pv=0,cpv=0,led=1,en_setzone=1,mac=FCDBB382E70B,adp_mode=run")
for word in string.gmatch(data, '([^,]+)') do
t[#t + 1] = word
end
local first = t[1]:gsub("%s+", "")
This gives me the string "ret=OK".
What can i do so that from this string to only get "OK", something like: get all from right of the equal sign and remove it and the left part. And this i must do for all the strings from "data" variable. Thank you.
I would recommend the following:
local data = 'ret=OK,type=aircon,reg=eu,dst=1,ver=2_2_5,pow=1,err=0,location=0,name=,icon=0,method=home only,port=30050,id=,pw=,lpw_flag=0,adp_kind=2,pv=0,cpv=0,led=1,en_setzone=1,mac=FCDBB382E70B,adp_mode=run'
local t = {}
for key, val in string.gmatch(data, '([^=,]*)=([^=,]*),?') do
t[key] = val
end
print(t['ret']) -- prints "OK"
print(t['adp_mode']) -- prints "run"
Note that the lua pattern makes the trailing comma optional (otherwise you miss the last keypair in the list).
Try this
for key, val in string.gmatch(data, "(%W*)=(%W*),") do
print(key.." equals "..val)
end
I am rolling up a huge table by counts into a new table, where I want to change all the empty strings to NULL, and typecast some columns as well. I read through some of the posts and I could not find a query, which would let me do it across all the columns in a single query, without using multiple statements.
Let me know if it is possible for me to iterate across all columns and replace cells with empty strings with null.
Ref: How to convert empty spaces into null values, using SQL Server?
To my knowledge there is no built-in function to replace empty strings across all columns of a table. You can write a plpgsql function to take care of that.
The following function replaces empty strings in all basic character-type columns of a given table with NULL. You can then cast to integer if the remaining strings are valid number literals.
CREATE OR REPLACE FUNCTION f_empty_text_to_null(_tbl regclass, OUT updated_rows int)
LANGUAGE plpgsql AS
$func$
DECLARE
_typ CONSTANT regtype[] := '{text, bpchar, varchar}'; -- ARRAY of all basic character types
_sql text;
BEGIN
SELECT INTO _sql -- build SQL command
'UPDATE ' || _tbl
|| E'\nSET ' || string_agg(format('%1$s = NULLIF(%1$s, '''')', col), E'\n ,')
|| E'\nWHERE ' || string_agg(col || ' = ''''', ' OR ')
FROM (
SELECT quote_ident(attname) AS col
FROM pg_attribute
WHERE attrelid = _tbl -- valid, visible, legal table name
AND attnum >= 1 -- exclude tableoid & friends
AND NOT attisdropped -- exclude dropped columns
AND NOT attnotnull -- exclude columns defined NOT NULL!
AND atttypid = ANY(_typ) -- only character types
ORDER BY attnum
) sub;
-- RAISE NOTICE '%', _sql; -- test?
-- Execute
IF _sql IS NULL THEN
updated_rows := 0; -- nothing to update
ELSE
EXECUTE _sql;
GET DIAGNOSTICS updated_rows = ROW_COUNT; -- Report number of affected rows
END IF;
END
$func$;
Call:
SELECT f_empty2null('mytable');
SELECT f_empty2null('myschema.mytable');
To also get the column name updated_rows:
SELECT * FROM f_empty2null('mytable');
db<>fiddle here
Old sqlfiddle
Major points
Table name has to be valid and visible and the calling user must have all necessary privileges. If any of these conditions are not met, the function will do nothing - i.e. nothing can be destroyed, either. I cast to the object identifier type regclass to make sure of it.
The table name can be supplied as is ('mytable'), then the search_path decides. Or schema-qualified to pick a certain schema ('myschema.mytable').
Query the system catalog to get all (character-type) columns of the table. The provided function uses these basic character types: text, bpchar, varchar, "char". Only relevant columns are processed.
Use quote_ident() or format() to sanitize column names and safeguard against SQLi.
The updated version uses the basic SQL aggregate function string_agg() to build the command string without looping, which is simpler and faster. And more elegant. :)
Has to use dynamic SQL with EXECUTE.
The updated version excludes columns defined NOT NULL and only updates each row once in a single statement, which is much faster for tables with multiple character-type columns.
Should work with any modern version of PostgreSQL. Tested with Postgres 9.1, 9.3, 9.5 and 13.