我有一个脚本,可以从多个单独的工作表和中央主工作表中收集和更新数据。 单个工作表可能包含30行,而主工作表将包含所有工作表中的所有行。
单张纸可能包含公式,例如= A2 + B2。在单个工作表上,此公式位于第2行,但在主工作表上,公式可能位于第400行。因此,公式工作并在主工作表中生成正确的数据,公式需要更改为= A400 + B400。 / p>
我尝试通过查找字符串中的单元格引用来完成此工作,该字符串在开头由字母字符分隔,后跟一个或多个数字以及末尾的空格或符号,迭代通过并将与该条件匹配的每一系列数字字符替换为新的数字值。成功有限。
以下是我到目前为止的尝试。
function isNumeric(n)
{
return !isNaN(parseFloat(n)) && isFinite(n);
}
function isAlpha(character)
{
if ((character.charCodeAt(0) >= 65 && character.charCodeAt(0) <= 90) ||(character.charCodeAt(0)>=97 && character.charCodeAt(0)<=122))
{
return true;
}
else
{
return false;
}
}
function correctFormula(formulaValue, destinationRow)
{
//parse through the string and identify cell references eg A2, AI77. (One or more consecutive letters followed by one or more consecutive numbers.
//Letters will never change but numbers will corresspond to the row in the array.
//ignore any text enclosed by ""
//ignore any text that does not start with =
var strFormulaValue = String(formulaValue);
if(strFormulaValue.charAt(0) === "=")
{
var i = 1;
var inQuotes = false;
var cellRef="";
var originalLength = strFormulaValue.length;
while (i<originalLength)
{
if (strFormulaValue.charAt(i)==="\"" || strFormulaValue.charAt(i)==="\'")
{
if (inQuotes)
{
inQuotes = false;
}
else
{
inQuotes = true;
}
}
if (strFormulaValue.charAt(i)==="!")
{
//this is a cell ref to another sheet. Get to the end of this ref
while((isAlpha(strFormulaValue.charAt(i)))||isNumeric(strFormulaValue.charAt(i)))
{
i++;
}
}
if (isNumeric(strFormulaValue.charAt(i)) &&(!inQuotes))
{
if(isAlpha(strFormulaValue.charAt(i - 1)))
{
//this looks like it could be the start of a cell ref
var numStart = i;
var numEnd = -1;
//find the last numerical digit in this sequence
while (isNumeric(strFormulaValue.charAt(i)))
{
if (isNumeric(strFormulaValue.charAt(i)))
{
numEnd = i;
}
i++
}
if ((!isAlpha(strFormulaValue.charAt(i)))||(i>=strFormulaValue.length))//if the sequence of numeric digits ends as a or the number digit was the last char in the string
{
//replace this string of numeric digits with the desired digits
var formulaStart = strFormulaValue.substring(0, numStart);
var formulaEnd = strFormulaValue.substring(numEnd + 1, strFormulaValue.length);
strFormulaValue = formulaStart+ String(destinationRow)+formulaEnd;
}
}
}
i++;
}
return strFormulaValue;
}
}
function testStrToFormula(stringval)
{
Logger.log ("Inputting =A12, should convert to A1000");
Logger.log (correctFormula("=A12", 1000));
Logger.log ("Inputting =A12 + B12, should convert to A1000 + B1000");
Logger.log (correctFormula("=A12 + B12 ", 1000));
Logger.log ("Inputting =sum(A12:D12), should convert to =sum(A1000:D1000)");
Logger.log (correctFormula("=sum(A12:D12)", 1000));
Logger.log("Inputting = A12 & \"D3\"");
Logger.log(correctFormula("=A12 & \"D3\""));
Logger.log("Inputting =Sheet1!A1 * B1")
Logger.log (correctFormula("=Sheet1!A1 * B1"))
}
记录
[18-03-01 17:36:34:853 GMT] Inputting =A12, should convert to A1000
[18-03-01 17:36:34:854 GMT] =A1000
[18-03-01 17:36:34:854 GMT] Inputting =A12 + B12, should convert to A1000 + B1000
[18-03-01 17:36:34:855 GMT] =A1000 + B1000
[18-03-01 17:36:34:856 GMT] Inputting =sum(A12:D12), should convert to =sum(A1000:D1000)
[18-03-01 17:36:34:858 GMT] =sum(A1000:D1000)
[18-03-01 17:36:34:859 GMT] Inputting = A12 & "D3"
[18-03-01 17:36:34:860 GMT] =Aundefined & "D3"
[18-03-01 17:36:34:861 GMT] Inputting =Sheet1!A1 * B1
[18-03-01 17:36:34:862 GMT] =Sheetundefined!A1 * B1
当我在处理引号中的值或对其他工作表中的单元格的引用时,不确定为什么我在字符串的中间未定义。 (不应改变对其他纸张上的单元格的引用)
答案 0 :(得分:0)
我认为最好的解决方案是让google工作表为您进行转换。您可以使用rng.copyTo(destinationRange)将公式和值复制到主工作表。这将保留值并更新公式引用。 (相当于手动复制和粘贴行)
以下是一个示例代码:
function copyFormula() {
var ss = SpreadsheetApp.getActive()
var sheet = ss.getSheetByName("TargetSheet")
var targetRng = sheet.getRange(1,1,1,3)
Logger.log(targetRng.getValues())
var desSheet = ss.getSheetByName("DestinationSheet")
var desRng = desSheet.getRange(desSheet.getLastRow()+1,1,1,3)
targetRng.copyTo(desRng)
}
此代码会将TargetSheet
的第1行(第1,2,3列)中的值和公式复制到DestinationSheet
的第一个可用行。它将保留硬编码值并自动更新公式。
答案 1 :(得分:0)
此代码有效,函数correctFormula(formula,destinationrow)将更新公式中的所有单元格引用,以匹配除绝对引用和外部引用之外的目标行。
function isNumeric(n)
{
return !isNaN(parseFloat(n)) && isFinite(n);
}
function isAlpha(character)
{
if ((character.charCodeAt(0) >= 65 && character.charCodeAt(0) <= 90) ||(character.charCodeAt(0)>=97 && character.charCodeAt(0)<=122))
{
return true;
}
else
{
return false;
}
}
function isFormulaDelimeter(character)
{
//=, +, -, /, *, :, %, [space], (,),", ',^,<,>,&,:
switch(character)
{
case "=":
return true;
break;
case "+":
return true;
break;
case "-":
return true;
break;
case "/":
return true;
break;
case "*":
return true;
break;
case ":":
return true;
break;
case "%":
return true;
break;
case " ":
return true;
break;
case "(":
return true;
break;
case ")":
return true;
break;
//=, +, -, /, *, :, %, [space], (,),", ',^,<,>,&,:
case "\"":
return true;
break;
case "\'":
return true;
break;
case "^":
return true;
break;
case "<":
return true;
break;
case ">":
return true;
break;
case "&":
return true
break;
case ":":
return true
break;
default:
return false;
}
}
function getTokens(formula) {
var strFormula = String(formula);
var index = 0;
var tokens = [];
while (index < strFormula.length)
{
var token = "";
while ((!isFormulaDelimeter(strFormula.charAt(index))) && (index < strFormula.length))
{
token = token + strFormula.charAt(index)
index ++;
}
tokens.push(token)
if (isFormulaDelimeter(strFormula.charAt(index)))
{
tokens.push(strFormula.charAt(index))
index++;
}
}
return(tokens);
}
function correctFormula(formulaValue, destinationRow)
{
//Logger.log(getTokens(formulaValue));
var tokens = getTokens(formulaValue);
var inQuotes = false;
for (var index = 0; index < tokens.length; index ++)
{
if ((String(tokens[index]).indexOf("\"")) !== -1 || (String(tokens[index]).indexOf("\'") !== -1) && (!inQuotes))
{
inQuotes = true;
}
else if(String(tokens[index]).indexOf("\"") !== -1 || (String(tokens[index]).indexOf("\'") !== -1) && (inQuotes))
{
inQuotes = false;
}
//if it's in quotes, dont touch it
if (!inQuotes)
{
//is it a cell reference?
//if it's an external cell reference dont touch it (contains !)
//if the number is preceded by a $ symbol, dont touch it
//TODO - absolute cell erf where letter part is absolute but not the number part.
var token = String(tokens[index]);
for (var n=0; n<token.length; n++)
{
//the cell references we are interested in are purely characters followed by numbers
if (isAlpha(token.charAt(0))||((String(token.charAt(0))==="$") && (isAlpha(token.charAt(1)))))//if its a cell ref or the first part is absolute
{
var itemRef = 1;
while(isAlpha(token.charAt(itemRef)))
{
itemRef++;
}
if (isNumeric(token.charAt(itemRef)))
{
var numStart = itemRef;
while(isNumeric(token.charAt(itemRef)))
{
itemRef ++;
}
if (itemRef == token.length)//if we are at the end and it was characters followed by numbers
{
var charPart = token.substring(0,numStart);
token = charPart + String(destinationRow);
tokens[index] = token;
}
}
}
}
}
}
//put it all back together and return the result
var formula = "";
for (n=0; n< tokens.length; n++)
{
formula = formula + String(tokens[n]);
}
return formula;
}