【问题标题】:Google Apps Script Utilities.parseCsv() change decimal and thousand separatorGoogle Apps Script Utilities.parseCsv() 更改小数点和千位分隔符
【发布时间】:2021-07-22 09:32:53
【问题描述】:

我是 GAS 新手,我正在努力解决我遇到的问题。 (我在网站上没有找到可以解决我问题的类似问题,因此我要问一个新问题)

目标:将 CSV 从 Google 云端硬盘导入 Google 表格
问题
csv 文件中的货币为“1,000.57” --> 美国格式
我需要的货币格式 "1.000,57" --> 欧洲格式

目前Utilities.parseCsv() 的格式被弄乱了,货币完全错误。

问题:有没有办法把“,”改成“.”和 ”。”在解析期间到“,”?如果是这样,由于csv的分隔符也是“,”,因此是否会出现进一步的问题。

我已经在网上找到了一些代码 sn-ps(不是我的代码:props to spreadsheet.dev)并尝试更改以下内容,但它似乎不起作用:

//Imports a CSV file in Google Drive into the Google Sheet
function importCSVFromDrive() {
  var fileName = promptUserForInput("Please enter the name of the CSV file to import from Google Drive:");
  var files = findFilesInDrive(fileName);
  if(files.length === 0) {
    displayToastAlert("No files with name \"" + fileName + "\" were found in Google Drive.");
    return;
  } else if(files.length > 1) {
    displayToastAlert("Multiple files with name " + fileName +" were found. This program does not support picking the right file yet.");
    return;
  }
  var file = files[0];
  var csvString = file.getBlob().getDataAsString()
  var escapedString = csvString.replace(",",".")
                                .replace(".",",");
  var contents = Utilities.parseCsv(escapedString);
  var sheetName = writeDataToSheet(contents);
  displayToastAlert("The CSV file was successfully imported into " + sheetName + ".");
}

//Prompts the user for input and returns their response
function promptUserForInput(promptText) {
  var ui = SpreadsheetApp.getUi();
  var prompt = ui.prompt(promptText);
  var response = prompt.getResponseText();
  return response;
}

//Returns files in Google Drive that have a certain name.
function findFilesInDrive(filename) {
  var files = DriveApp.getFilesByName(filename);
  var result = [];
  while(files.hasNext())
    result.push(files.next());
  return result;
}

//Inserts a new sheet and writes a 2D array of data in it
function writeDataToSheet(data) {
  var ss = SpreadsheetApp.getActive();
  sheet = ss.insertSheet();
  sheet.getRange(1, 1, data.length, data[0].length).setValues(data);
  return sheet.getName();
}

我做错了什么?

【问题讨论】:

  • 您的 csv 文件的实际分隔符是什么?是分号吗?也许你可以拿这个代码gist.github.com/IranthaJ/…
  • @MikeSteelson 感谢迈克的快速回答。我的 CSV 文件实际上有逗号作为分隔符。我尝试了您提供的代码,但不幸的是它导致了以下错误:“异常:在对象 DriveApp.importCSV 上获取方法或属性 getFolderById 时出现意外错误”
  • 你能给我们一个你的 csv 文件的样本吗?它在哪里?
  • 如果分隔符是逗号,,那么单元格内包含逗号的任何数据都应该用引号"(在propper CSV中)。在这种情况下,您可以查找并替换引用文本中的任何逗号。没什么大不了的。虽然如果您的数据包含引号内的引号......所以解决方案在很大程度上取决于您的数据。没有通用的通用解决方案。
  • var escapedString = csvString.replace(",",".").replace(".",","); 太搞笑了。一个常见的错误。你会在任何地方得到逗号(如果你设法替换所有,而不仅仅是一个字母)。在这种情况下,您需要三个步骤:替换, --> _ 然后替换. --> , 然后替换_ --> .

标签: csv google-apps-script google-sheets


【解决方案1】:

Utilities.parseCsv() 是一团糟。我建议你不要使用它。相反,请尝试Advanced Google Service - Drive V2

您需要在服务下添加云端硬盘。

这是您需要的代码 sn-p:

function insertFromCsv(fileName) {
  var blob = DriveApp.getFilesByName(fileName).next().getBlob();
  var tempFile = Drive.Files.insert({title: "tempSheet"}, blob, {
      convert: true
  });
  var tempSsId = tempFile.getId();
  var tempSheet = SpreadsheetApp.openById(tempSsId).getSheets()[0];
  var newSheet = tempSheet.copyTo(SpreadsheetApp.getActive());
  DriveApp.getFileById(tempSsId).setTrashed(true);
  return newSheet.getName();
}

并将importCSVFromDrive更改如下:

function importCSVFromDrive() {
  var fileName = promptUserForInput("Please enter the name of the CSV file to import from Google Drive:");
  var files = findFilesInDrive(fileName);
  if(files.length === 0) {
    displayToastAlert("No files with name \"" + fileName + "\" were found in Google Drive.");
    return;
  } else if(files.length > 1) {
    displayToastAlert("Multiple files with name " + fileName +" were found. This program does not support picking the right file yet.");
    return;
  }
  var file = files[0];
  // var csvString = file.getBlob().getDataAsString()
  // var escapedString = csvString.replace(",",".")
  //                               .replace(".",",");
  // var contents = Utilities.parseCsv(escapedString);
  // var sheetName = writeDataToSheet(contents);
  var fileName = file.getName();
  var sheetName = insertFromCsv(fileName);

  displayToastAlert("The CSV file was successfully imported into " + sheetName + ".");
}

【讨论】:

  • 非常感谢,这听起来很有希望。我按照您的指示:在服务下的版本 V2 中添加驱动器并运行您的代码 sn-p:不幸的是,提示以下错误:“异常:无效参数:名称”我是否需要更改其他内容?
  • 只是猜测。也许您需要在调用函数之前定义fileName。大概应该是var fileName = "Test_data_2.csv"
  • 我不知道您为什么或从哪里收到该消息。我在上面编辑了答案以添加工作表名称的返回,并向您展示如何在代码中调用我的函数。
  • @AlsoRan:感谢您的更新版本。它现在运行良好。但是在输出中,解析仍然必须做对吗?因为现在的输出看起来非常像 csv 中的输入。
  • @Bierbaron1920:一个 csv 文件不应该有数字分隔符,除非生成文件的应用程序认为它是一个文本字段。导入后数字列的格式是什么?谷歌表格的语言环境是什么?
【解决方案2】:

因此,您的 CSV 数据样本在这里:https://drive.google.com/file/d/1ASevYOWtu8YL6YA4w-UqDuNXAS0RfaJF/view?usp=sharing

在我看来,它就像普通的 CSV 数据:

Trades,Header,DataDiscriminator,Asset Category,Currency,Symbol,Date/Time,Quantity,T.Price
Trades,Data,Order,Stocks,USD,ALGN,"2021-06-28,10:50:27",3,627.17,621.52,-1881.51,-1,1882.51,0,-16.95,O
Trades,Data,Order,Stocks,USD,AMAT,"2021-06-29,09:38:53",14,142.15,141.92,-1990.1,-1,1991.1,0,-3.22,O
Trades,Data,Order,Stocks,USD,APH,"2021-07-02,09:30:01",30,69.438,69.95,-2083.14,-1,2084.14,0,15.36,O

我看不到“欧洲”格式的数字。

相信可以正确解析成这样:

Trades Header DataDiscriminator Asset Category Currency Symbol Date/Time Quantity T.Price
Trades Data Order Stocks USD ALGN "2021-06-28,10:50:27" 3 627.17 621.52 -1881.51 -1 1882.51 0 -16.95 O
Trades Data Order Stocks USD AMAT "2021-06-29,09:38:53" 14 142.15 141.92 -1990.1 -1 1991.1 0 -3.22 O
Trades Data Order Stocks USD APH "2021-07-02,09:30:01" 30 69.438 69.95 -2083.14 -1 2084.14 0 15.36 O

我没有尝试用Utilities.parseCsv() 来做,我写了自己的小 csv-parser,只是为了确保任务是可行的并且我的假设是正确的:

var s = `Trades,Header,DataDiscriminator,Asset Category,Currency,Symbol,Date/Time,Quantity,T.Price
Trades,Data,Order,Stocks,USD,ALGN,"2021-06-28,10:50:27",3,627.17,621.52,-1881.51,-1,1882.51,0,-16.95,O
Trades,Data,Order,Stocks,USD,AMAT,"2021-06-29,09:38:53",14,142.15,141.92,-1990.1,-1,1991.1,0,-3.22,O
Trades,Data,Order,Stocks,USD,APH,"2021-07-02,09:30:01",30,69.438,69.95,-2083.14,-1,2084.14,0,15.36,O`;

// replace ',' with '_' inside quotes
s.match(/("[^,]+),(.+")/g).forEach(t=>s=s.split(t).join(t.replace(/,/g,'_')));

// replace ',' with '\t', replace '_' with ',' and split string into 2-d array
var array = s.replace(/,/g,"\t").replace(/_/g,',').split('\n').map(x => x.split('\t'));

console.table(array);

输出:

┌─────────┬──────────┬──────────┬─────────────────────┬──────────────────┬────────────┬──────────┬─────────────────────────┬────────────┬───────────┬──────────┬────────────┬──────┬───────────┬─────┬──────────┬─────┐
│ (index) │    0     │    1     │          2          │        3         │     4      │    5     │            6            │     7      │     8     │    9     │     10     │  11  │    12     │ 13  │    14    │ 15  │
├─────────┼──────────┼──────────┼─────────────────────┼──────────────────┼────────────┼──────────┼─────────────────────────┼────────────┼───────────┼──────────┼────────────┼──────┼───────────┼─────┼──────────┼─────┤
│    0    │ 'Trades' │ 'Header' │ 'DataDiscriminator' │ 'Asset Category' │ 'Currency' │ 'Symbol' │       'Date/Time'       │ 'Quantity' │ 'T.Price' │          │            │      │           │     │          │     │
│    1    │ 'Trades' │  'Data'  │       'Order'       │     'Stocks'     │   'USD'    │  'ALGN'  │ '"2021-06-28,10:50:27"' │    '3'     │ '627.17'  │ '621.52' │ '-1881.51' │ '-1' │ '1882.51' │ '0' │ '-16.95' │ 'O' │
│    2    │ 'Trades' │  'Data'  │       'Order'       │     'Stocks'     │   'USD'    │  'AMAT'  │ '"2021-06-29,09:38:53"' │    '14'    │ '142.15'  │ '141.92' │ '-1990.1'  │ '-1' │ '1991.1'  │ '0' │ '-3.22'  │ 'O' │
│    3    │ 'Trades' │  'Data'  │       'Order'       │     'Stocks'     │   'USD'    │  'APH'   │ '"2021-07-02,09:30:01"' │    '30'    │ '69.438'  │ '69.95'  │ '-2083.14' │ '-1' │ '2084.14' │ '0' │ '15.36'  │ 'O' │
└─────────┴──────────┴──────────┴─────────────────────┴──────────────────┴────────────┴──────────┴─────────────────────────┴────────────┴───────────┴──────────┴────────────┴──────┴───────────┴─────┴──────────┴─────┘

如果您添加range.setValues(array) 而不是console.table(array),您可能会在您的工作表中获得一个道具表。

更新

要替换数组中的123.45 --> 123,45 需要在末尾添加一行:

array = array.map(row => row.map(cell => cell.replace(/(\d)\.(\d)/g, '$1,$2')));

【讨论】:

  • 嗨,尤里,非常感谢!你是对的,csv中的数据不是欧洲的,而是美国的。目标是拥有欧洲人。因此,使用您自己编写的 csv 解析器,您就能够完成任务。好的!我需要的输出的唯一更改是:'-1881,51' 而不是 '-1881.51'(将“.”更改为“,”)。
  • 那么您需要帮助吗?
  • 请。 1) 随着输出从“-1881.51”到“-1881,51”的变化。 2)你的最终代码会是什么样子。对不起,我只是在挣扎。谢谢
  • 我刚刚更新了我的答案。您只需添加一行即可修改数组的内容。将数组放在工作表上时遇到问题吗?
  • 非常感谢尤里的工作!解决了这个问题!
【解决方案3】:

我创建一个csv文件并在这里​​测试https://docs.google.com/spreadsheets/d/148muW2MhTBwXfppFhO85gQv6GRduvyb5OMHeS68VWH4/edit?usp=sharing

function importCsvFromId() {
  var id = '1yc04iLf20k6oVlwSMpWm-xythMPKJoBO';
  var csv = DriveApp.getFileById(id).getBlob().getDataAsString();
  var csvData = Utilities.parseCsv(csv);
  var f = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet()
  f.getRange(1, 1, csvData.length, csvData[0].length).setValues(csvData);
}

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-18
  • 2013-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多