how to avoid large numbers from converting to Exponential in nodejs excel file read - node.js

I am want to read excel file having phone numbers stored as numbers but when I read the file using SheetJS/js-xlsx (npm install xlsx), All the large phone numbers are converted to strings like
9.19972E+11
919971692474 --> 9.19972E+11
My code is
var workbook = XLSX.readFile(req.files.fileName.path);
var sheet_name_list = workbook.SheetNames;
var csvFile = XLSX.utils.sheet_to_csv(workbook.Sheets[sheet_name_list[0]]);
console.log(csvFile2);
console output is
customer_phone,product_name
9.19972E+13,"Red Belly Shoes,"
Is there any way I can avoid such conversion?

The number 919971692474 is normally displayed as 9.19972E+11 in Excel. To force it to display the full number you have to set the number format to 0 (right click, format cell, choose custom type '0'). And when you do that, the full number is displayed. If you don't set a format in excel, the xlsx module uses the "General" format and that number format displays the phone number as an exponential.
If the file is incorrect, you can override the CSV formatting by deleting the w key and adding a z key corresponding to the desired number format. For example, to change cell A2:
var sheet = workbook.Sheets[workbook.SheetNames[0]];
delete sheet.A2.w;
sheet.A2.z = '0';
If you want to do this for all number cells, just loop:
Object.keys(sheet).forEach(function(s) {
if(sheet[s].w) {
delete sheet[s].w;
sheet[s].z = '0';
}
});

By default sheet_to_csv take the formatted numbers.
- To avoid the formatted value and to take raw inputs (original values) you have to add parameter in sheet_to_csv method you have to set rawNumbers to true
Try this code
var csvFile = XLSX.utils.sheet_to_csv(workbook.Sheets[sheet_name_list[0]], { rawNumbers: true });

It seems in later versions w is not there. That's how it could be done in recent versions.
const ws = XLSX.utils.json_to_sheet(data);
Object.keys(ws).forEach(function(s) {
if(ws[s].t === 'n') {
ws[s].z = '0';
ws[s].t = 's';
}
});
const csv = XLSX.utils.sheet_to_csv(ws);

Using sheet[s].z = '0'; works in removing the scientific notation, but it also removes any decimal places you might want to retain. From the readme:
The cell.w formatted text for each cell is produced from cell.v and cell.z format.
I was able to remove the scientific notation by explicitly setting the value of w instead of letting xlsx calculate it for me:
if (cell.t === 'n') {
cell.w = cell.v;
}

Related

Excel VSTO cell precision

When I read very small values from Excel sheet these are shown as scientific precision. For example, the -0.00002 is always read as -2E05 using Cells().Values function. Below are the conversion lines I have used, without any success. How to get the actual value instead of the scientific format?
var canConvert = decimal.TryParse(ws.Cells[1, 1].Value.ToString(), out _); // result in false
var cellString = ws.Cells[1, 1].Value.ToString("R"); // -2E05
var cellStrin2g = ws.Cells[1, 2].Value.ToString(); // -2E05
It seems you need to set up the required NumberFormat first:
ws.Range("A17").NumberFormat = "General"
The format code is the same string as the Format Codes option in the Format Cells dialog box.
After several trial I have came up to the following solution, which works well in my model.
double number = 0;
var canConvert = double.TryParse(ws.Cells[row, column].Value.ToString(), out number3);
if (canConvert)
string doubleAsString = cell.ToString("F99").TrimEnd('0');
Bear in mind that the above scenario works well upto 99 following digits. Feel free to extend it to your needs.

PHPExcel prevent calculating formula

I'm trying to convert a CSV file to a XLSX file using PHPExcel library. Once the csv file is read into PHPExcel object and before saving it as a xlsx file, I recalculate and set column widths based on relevant column content.
$objReader = PHPExcel_IOFactory::createReader('CSV');
$objPHPExcel = $objReader->load("test.csv");
$activesheet = $objPHPExcel->getActiveSheet();
$lastColumn = $activesheet->getHighestColumn(); // get last column with data
$lastColumn++;
for ($column = 'A'; $column != $lastColumn; $column++) { // for each column until last
$activesheet->getColumnDimension($column)->setAutoSize(true); // set autowidth
}
$objWriter = PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
$objWriter->save("downloads/test.xls");
with bit of a research i found that if there are any formulas in the file, call to setAutoSize() calculates the value for them to make use when calculating the column width.
My problem is that some of my csv files contain values that begins with = (equal sign) which are not formulas. for ex. cell values like '===='. This causes above code to throw an error PHPExcel_Calculation_Exception Formula Error: An unexpected error occured.
Since I know that any of my input csv files cannot contain formulas, is there a way to prevent PHPExcel calculating values for cells which contain values beginning with = sign?
After research and given suggestions I ended up iterating through all the cells and rewriting cell values (beginning with = sign), to prevent PHPExcel considering them as formulas. setCellValueExplicit() method instructs PHPExcel to not consider the cell value as a formula in this case.
foreach ($objPHPExcel->getWorksheetIterator() as $worksheet) {
foreach ($worksheet->getRowIterator() as $row) {
$cellIterator = $row->getCellIterator();
$cellIterator->setIterateOnlyExistingCells(true);
foreach ($cellIterator as $cell) {
if (preg_match( '/^=/', $cell->getValue())) {
$cellcoordinate = $cell->getCoordinate();
$worksheet->setCellValueExplicit($cellcoordinate,$worksheet->getCell($cellcoordinate));
}
}
}
}
It's painful, but couldn't find a better solution.

Getting Cell as String in PHPExcel by column and row

I am trying to read a cell with possible trailing zeros as a string instead of numeric (which strips off leading zeros). The cell is read by integer column/row as below instead of column string as this answer has.
initial code
$instReader = $reader->load($this->file);
$sheet = $instReader->getSheet(0);
I tried modifying this from:
$keyCell = $sheet->getCellByColumnAndRow(1,5);
to:
$sheet->setCellValueExplicitByColumnAndRow(1,5, PHPExcel_Cell_DataType::TYPE_STRING);
$keyCell = $sheet->getCellByColumnAndRow(1,5);
the former gives 1407 for $keyCell instead of 01407
the latter gives "s" or ""
how do I treat the cell as string before calling getCellByColumnAndRow and using only integer values for column and row.
(BTW, if this can be done once for an entire column instead of each time for each individual cell that would be better)
$keyCell = $sheet->getCellByColumnAndRow(1,5)->getValue();
Will read the cell data in the format that it's actually stored by Excel, you can't arbitrarily change that or tell PHPExcel to read it as a different datatype.
However, if the cell has formatting applied, then you can use
$keyCell = $sheet->getCellByColumnAndRow(1,5)->getFormattedValue();
instead, and this will return the data as a string, with whatever format mask was defined in the Excel spreadsheet
Same issue for me. I become crazy.
Tried to set
$objReader->setReadDataOnly(true);
wasn't working
tried
$sheet->getCellByColumnAndRow(4,$row)->getValue()
because normaly display text as raw => doesn't working.
So last I change code in library. Edit file named DefaultValueBinder.php
Search for dataTypeForValue function and set this :
} elseif (is_float($pValue) || is_int($pValue)) {
return PHPExcel_Cell_DataType::TYPE_STRING;//TYPE_NUMERIC patch here;
} elseif (preg_match('/^\-?([0-9]+\\.?[0-9]*|[0-9]*\\.?[0-9]+)$/', $pValue)) {
return PHPExcel_Cell_DataType::TYPE_STRING;//TYPE_NUMERIC patch here;
So now return numbers with 0

phpexcel reading an excel file decimal numbers are read incorrectly

I've got the value '9,2' (dutch notation of '9.2') within a cell of a .xlsx file, the cell has a 'general' number format. Also the value in the upper bar where you also view formulas says '9,2' When I read this cell with PHPExcel with ->getValue() I get '9,199999999999999'.
This is my code:
$oPhpReader = PHPExcel_IOFactory::createReader($sFileType);
$aWorksheetNames = $oPhpReader->listWorksheetNames($sFileName);
$oPhpReader->setReadDataOnly(true);
$oPhpReader->setLoadSheetsOnly($aWorksheetNames[0]);
$oPhpExcel = $oPhpReader->load($sFileName);
$oWorksheet = $oPhpExcel->getActiveSheet();
$oCell = $oWorksheet->getCellByColumnAndRow($iCol,$iRow);
$sTempValue = $oCell->getValue();
This is the way I solved my problem now. Though I do not think this is a very neat solution, it is probably the only way.
I just figured I will never get numbers with more than 12 digits, only when PHPExcel get them wrong. So I round all my floats to 12 digit using number_format:
if ((is_numeric($sTempValue))&&(strpos($sTempValue,'.')))
{
$sTempValue = rtrim(rtrim(number_format($sTempValue,12,',',''),'0'),',');
}

My Excel file of CSV data from Google Apps Script doesn't mirror my Google Spreadsheet

I'm trying to write a script that passes information from a Google Spreadsheet, compiles it into a CSV file and emails that file.
My problem: The CSV file on my Excel file looks very different that of my Google Spreadsheet (Dead link).
This is what my Excel file looks like, pasted into another Google Spreadsheet.
The code I am using is below:
function myFunction() {
//get active sheet, the last row where data has been entered, define the range and use that range to get the values (called data)
var sheet = SpreadsheetApp.getActiveSheet();
var lastRow=sheet.getLastRow();
var range = sheet.getRange(1,1,lastRow,91);
var data = range.getValues();
//define a string called csv
var csv = "";
//run for loop through the data and join the values together separated by a comma
for (var i = 0; i < data.length; ++i) {
csv += data[i].join(",") + "\r\n";
}
var csvFiles = [{fileName:"example.csv", content:csv}];
MailApp.sendEmail(Session.getUser().getEmail(), "New Journey Information", "", {attachments: csvFiles});
}
You need to ensure that individual cells' data is atomic. For instance, what you see as a time on the sheet contains a Date object when read by your script, then when that's written to a CSV it may be converted to a date & time string with commas, depending on your locale. (Jan 4, 2013 14:34 for example.) To be safe with punctuation that may be interpreted as delimiters by Excel, you should enclose each element with quotes.
No need to modify your code, as this problem has been solved in one of the examples provided in the Docslist Tutorial. So an easy solution is to replace your code.
Change the first bit of the provided saveAsCSV() as follows, and it will operate either with user input or by passing a filename as a parameter.
function saveAsCSV(filename) {
// Prompts the user for the file name, if filename parameter not provided
fileName = filename || Browser.inputBox("Save CSV file as (e.g. myCSVFile):");
...

Resources