如何防止Google表单将表单输入转换为科学计数法格式

时间:2015-06-10 15:56:18

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

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

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

我需要用户在eGCs字段中输入的内容在他们在回复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。它应该是公开的,所以请随意测试它。

2 个答案:

答案 0 :(得分:2)

表单中的表单(与Spreadsheets相对)将响应存储为字符串。您的触发器功能可以从表单中获取响应以获取响应者输入的字符串。

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);
}

注意wrt 竞争条件评论:代码的这个区域所需的实际工作是一行:

var responses = form.getResponses(timestamp);

在玩这个游戏时,我发现我经常收到一个例外情况,就像下面评论中提到的那样......

  

无法找到方法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));

不止一行代码,但更强大。

答案 1 :(得分:1)

我假设 eGCs 是带号码的回复。

e.values [2]将始终以字符串形式返回(在本例中为“6.15312E + 16”),因此您无法将其转换为原始数字,因为您在最后一次之后丢失了所有内容。即使您转换它,你能得到的最好的是“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);
 }

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

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

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

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