【问题标题】:How to prevent Google Forms from converting form input to scientific notation format如何防止 Google Forms 将表单输入转换为科学记数法格式
【发布时间】:2015-06-10 15:56:18
【问题描述】:

我有一个简单的脚本设置,它使用基于脚本的 VLookup 根据 Google 表单条目发送电子邮件以获取联系电子邮件。在某些情况下,Google 表单会将输入到表单字段中的较长数字转换为科学记数法。我一直在使用的一种解决方法是在数字前输入撇号 - 出于某种原因,这会将单元格格式化为纯文本。我想找到一个不需要这个额外步骤的解决方案。

工作表有一个带有单个字段 eGCs 的表单。 eGCs 字段可以包含字母和数字的任意组合,并且可以是多行字符串。该脚本向用户 onFormSubmit 发送一封电子邮件,电子邮件正文中包含 eGCs 字段条目。当我尝试提交一个非常长的只有数字的字符串并且表单输入变量被转换为科学计数法时,就会出现问题。

我需要用户在 eGCs 字段中输入的内容与他们在 Responses 1 表和发送的电子邮件正文中输入的内容完全相同。代码如下:

function onFormSubmit(e) {

   var eGCs = e.values[1];
   var email = Session.getActiveUser().getEmail();

//Replace the Google Sheets formatted line breaks with HTML line breaks so they display properly in the email:
   eGCs = eGCs.replace(/\n/g, '<br>');

//Send the email:   
   var subject = "This is only a test";
   var body = eGCs;
   MailApp.sendEmail(email, subject, body, {htmlBody: body})
   return
   }

如果我提交

6110523527643880 

...进入表单,数字变为科学计数法格式,并在工作表和发送的电子邮件中显示为6.11052E+15。如果我提交一个多行字符串,例如:

6110523527643880
6110523527643880
6110523527643880

...然后脚本工作正常并且表单字段条目未转换(可能是因为 Google 不再将其视为数字)。无论表单条目是单行还是多行,我都需要它与输入的内容完全相同。

这是我的example sheet / script / form。它应该是公开的,所以请随意测试它。

【问题讨论】:

  • 转换它的是表格还是电子表格?您是否尝试过将格式更改为电子表格中的格式?
  • 嗨斯宾塞 - 我不确定。如果这有帮助,此人正在处理的问题与此相同:productforums.google.com/forum/m/#!msg/docs/dMIAKVtuKW0/… 我怀疑在此过程中,Google 正在将单元格改回“自动”格式而不是“纯文本”格式。我在电子表格中将整列设置为“纯文本”格式,但这似乎无关紧要。我尝试使用那些 cmets 中某人建议的脚本,但仍然没有运气。
  • 我创建了一个虚拟表,以便您自己查看它的运行情况。将其添加到顶部的原始帖子中。
  • 向前勾号使单元格内容成为文本 - 这是 Excel、Lotus 1-2-3 甚至 VisiCalc 中的标准符号。但是,您真正的问题是表格中的单元格格式,完全独立于表单。您可以让触发函数使用Range.setNumberFormats() 应用适当的格式。向您的 cmets 发送关于通过提交更改格式的信息...关闭!提交表单会插入一个具有自动格式设置的新行。
  • 感谢您的意见,莫格兹达。您复制的线程底部的解决方案在这种情况下不起作用,因为正如您所说,正在将新行添加到不保留应用于列其余部分的格式的工作表中。至于您的 setNumberFormats() 解决方案,我可以在 onFormSubmit 触发器发送电子邮件之前将其应用于新创建的行吗?或者我是否需要在链中进一步向上或向下移动其中一个触发器才能使其起作用?不幸的是,我不确定我是否有足够的 JavaScript 经验来实现这一点而无需指导。

标签: google-apps-script google-sheets google-docs google-forms


【解决方案1】:

表单响应在表单中(相对于电子表格)将响应存储为字符串。您的触发函数可以从表单中获取响应以获取响应者输入的字符串。

function onFormSubmit(e) {
  // Get response sheet. First version works only in contained script,
  // second works even in stand-alone scripts.
//  var sheet = SpreadsheetApp.getActiveSheet();
  var sheet = e.range.getSheet();

  // Get URL of associated form & open it
  var formUrl = sheet.getParent().getFormUrl();
  var form = FormApp.openByUrl(formUrl);

  // Get response matching the timestamp in this event
  var timestamp = new Date(e.namedValues.Timestamp);
  // NOTE: There is a race condition between the updates in Forms and Sheets.
  // Sometimes (often!) the Spreadsheet Form Submission trigger function is invoked
  // before the Forms database has completed persisting the new Responses. As
  // a result, we might get no results when asking for the most recent response. 
  // To work around that, we will wait and try again.
  var timeToGiveUp = 0;
  do {
    if (timeToGiveUp > 0) Utilities.sleep(1000); // sleep 1s on subsequent tries
    timeToGiveUp++;
    var responses = form.getResponses(timestamp);
  } while (responses.length == 0 && (timeToGiveUp < 3));
  Logger.log("time to give up "+timeToGiveUp);
  var response = responses[0]; // assume just one response matches timestamp
  var itemResponses = response.getItemResponses();
  var eGCsItemNumber = 1;  // Indicates where the question appears in the form
  var eGCs = itemResponses[eGCsItemNumber-1].getResponse().toString();

  // You now have exactly what the respondent typed, as a string.
  // It can be used as-is in an email, for example.
  var body = "The user entered: "+eGCs;
  MailApp.sendEmail(
     Session.getActiveUser().getEmail(),
     "This is only a test",
     body
   );

  // To preserve the value in the spreadsheet, we must
  // force it to remain a string by prepending a tick (')
  var eGCsCol = 2;
  e.range.offset(0,eGCsCol-1,1,1).setValue("'"+eGCs);
}

Note wrt Race condition 注释:该代码区域所需的实际工作是一行:

var responses = form.getResponses(timestamp);

在玩这个的时候,我发现我经常收到一个异常,和这个答案下面的 cmets 中提到的一样......

找不到方法 getResponses(object)

事实证明,这只发生在函数由表单提交事件触发时,而不是从编辑器/调试器运行模拟事件时发生。这意味着,在短时间内,我们试图处理的响应不会通过对getResponses() 的调用返回。

由于共享文档的实现方式,任何更改都存在传播延迟...这是资产的一个视图中的更改传播到所有其他视图所需的时间意见。

在这种情况下,我们的触发器函数已通过电子表格事件启动,然后打开表单视图并尝试读取最新的响应之前该视图包含它们。

一个简单的解决方法是在一段时间内sleep() 允许传播完成。

Utilities.sleep(5000);   // 5s pause
var responses = form.getResponses(timestamp);

简单,是的 - 但效率低下,因为即使我们不需要等待,我们也会等待。第二个问题是确定多长时间才够长……如果明天改变了怎么办?

仅当第一次未成功时,选择的解决方法才会重新尝试获取响应。它只会在重试时等待。它不会永远等待 - 通过timeToGiveUp 应用了一个限制条件。 (我们本可以在循环之后添加一个额外的成功检查,但由于如果我们超过了时间限制,下一条语句将通过异常,我们可以让它做脏活。)

var timeToGiveUp = 0;
do {
  if (timeToGiveUp > 0) Utilities.sleep(1000); // sleep 1s on subsequent tries
  timeToGiveUp++;
  var responses = form.getResponses(timestamp);
} while (responses.length == 0 && (timeToGiveUp < 3));

不止一行代码,但更健壮。

【讨论】:

  • 感谢您继续致力于解决此问题,Mogsdad。我会尝试用我的代码实现你的代码并报告。
  • 我收到了失败摘要:2015 年 6 月 17 日下午 3:27 onFormSubmit 找不到方法 getResponses(object) - 我将我们的代码添加到顶部问题的底部,以便您可以看看我尝试了什么。
  • 在这种情况下 itemResponses[2] 是否应该是 itemResponses[1],因为 eGCs 列现在位于简化表的 B 列中?
  • 我重新添加了触发器,现在我得到了失败摘要:无法检索表单响应。请稍候再试。 (第 8 行,文件“代码”)。我现在得走了,但再次感谢您的帮助。
  • 我觉得这与我正在寻找的答案非常接近。我现在无法弄清楚如何使这段代码工作。我知道我需要像您在上面所做的那样将表单响应存储为变量,但我仍然得到相同的失败摘要
【解决方案2】:

我假设 eGCs 是带有数字的响应。

e.values[2] 将始终作为字符串返回(在本例中为“6.15312E+16”),因此您无法将其转换为原始数字,因为您在最后 2 之后丢失了所有内容。即使您转换它,你能得到的最好的是“61531200000000000”

相反,您可以从电子表格中提取值。 在 onFormSubmit() 函数的开头添加以下代码:

 var ss = SpreadsheetApp.getActiveSpreadsheet();
 var sheet = ss.getSheetByName("Form Responses 1");
 var eGCs = sheet.getRange(sheet.getLastRow(), 2, 1, 1).getValue(); 
 try {
   eGCs = eGCs.toFixed();
 } catch (e) {
   Logger.log(eGCs);
 }

如果是数字,您的 eGC 现在将以完整数字返回,否则将以文本形式返回。

如果您希望电子表格在提交新回复时具有正确的格式,请将其添加到您的代码中:

sheet.getRange(sheet.getLastRow(), 2, 1, 1).setNumberFormat("000");

这会将表单添加的新行转换为正确的格式。这不会影响电子表格中的实际值,只会影响其格式。

【讨论】:

  • 感谢您的建议 - 我今天会尝试并报告。
  • 嗨 Ashkin - 我能够让您的代码正常工作(左侧有一个时间戳列,所以我不得不将 getLastRow(), 2, 1, 1) 更改为 getLastRow(), 3 , 1, 1)。该数字在电子邮件中保持其格式,但由于某种原因未转换工作表。我会处理这部分工作并回复您。
  • 不幸的是,这对我的目的不起作用,因为表单上的 eGCs 字段有时需要输入多行数字,在这种情况下它的行为很奇怪。感谢您的帮助,因为您让我比以前更接近了,但仍然没有按照我的需要工作。
  • 抱歉让事情变得困难 - 我没有意识到将数据保持在与输入相同的格式这样简单的事情会是一个巨大的考验。
  • 您能否举例说明 eGC 的外观?
猜你喜欢
  • 2020-10-28
  • 2019-03-24
  • 2012-07-20
  • 1970-01-01
  • 2022-10-10
  • 2018-11-27
  • 2019-06-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多