How to get all sheet names without trimming? - phpspreadsheet

I have excel file with sheet names utf-8, and I got trimmed sheet name because this sheet title is more then 31 characters.
My code:
<?php
use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\IOFactory;
$reader = IOFactory::createReader('Xlsx');
$reader->setReadDataOnly(TRUE);
$spreadsheet = $reader->load('/home/cool-file.xlsx');
$all = $spreadsheet->getSheetNames();
In $all variable I got a list of all sheet names but all names are trimmed.
I tried to comment this part of code:
https://github.com/PHPOffice/PhpSpreadsheet/blob/develop/src/PhpSpreadsheet/Worksheet/Worksheet.php#L853-L882
but no changes.

use PhpOffice\PhpSpreadsheet\Reader\Xlsx;
use PhpOffice\PhpSpreadsheet\IOFactory;
$reader = IOFactory::createReader('Xlsx');
$reader->setReadDataOnly(TRUE);
$spreadsheet = $reader->load('/home/cool-file.xlsx');
$all = $spreadsheet->getSheetNames()[1];
Please, note the bracket and the ID of the sheet

Related

Formula to import multiple columns to 1 column if a name from a different list matches any name in those columns

Looking for a way to import a long range of columns in to 1 list if a name from a different list matches any name in that particular column. I've tried a couple variations of query, filter, vlookup... Can't seem to find the right combination. Example..
List A on sheet 1 contains the names Jim, John and James. On a separate sheet, there are 5 columns containing names. Column 1 contains Jim, Alex and Ben. Column 2 contains Harold, Bob and Jimmy. Column 3 contains James, Jeremy and Felix. Column 4 contains James, Eric and Evan. Column 5 contains Sara, Jamie and Xavier. The end result should display the list in 1 column to contain the names - Jim, John, James, Alex, Ben, Jeremy, Felix, Eric and Evan. Columns 1, 3 and 4 would be imported to a single list because at least 1 name within those columns matched a name in the original list.
Example sheet.
UPDATED
You can try this sample implementation below using Apps Script custom function. Just copy and paste it to your spreadsheet file as a bound script:
NOTE: This script will check each name listed on the "Main List" & if each of them has matches on multiple columns on the second sheet Sheet2, then it will place all of the names on columns that contains any matched name on the "Imported List". The only catch using this implementation is that it'll run a bit slow when there's a huge amount of data to be processed.
SCRIPT
function onOpen(){ //Runs every time you open the spreadsheet
FINDMATCH();
}
function onEdit(){//Runs every time you make an edit to the sheet
FINDMATCH();
}
function FINDMATCH() { //Function to check each columns on "Sheet2" to see if it has names that match any names on the "Main List"
var main = SpreadsheetApp.getActive().getSheetByName("Sheet1");
var mainList = [].concat.apply([], main.getRange("A4:A").getValues()).filter(String); //Main list data starts at A4
var sheet2 = SpreadsheetApp.getActive().getSheetByName("Sheet2"); //Name of the Sheet2
var result = mainList;
for(col=1; col <= sheet2.getDataRange().getLastColumn(); col++){
// E.G. if you only want to set the maximum of 2 rows as seen below, the "currentCol" code will only scan range A1:F3 on Sheet2 because the number 3 on the third parameter of the getRange() method will be the maximum row to be scanned.
var currentCol = [].concat.apply([], sheet2.getRange(1,col,2,1).getValues()).filter(String);
mainList.forEach(function(list){
currentCol.forEach(function(data){
if(data == list){
result.push(currentCol.toString());
return;
}
});
});
}
var data = FILTER(result.toString().trim().split(","));
main.getRange("AG4:AG").clearContent(); //Clears the old "Imported List" data before pasting updated list of names
main.getRange(4,33,data.length,1).setValues(data); //Updates the "Imported List"
}
function FILTER(array) { //Function that filters duplicate names
var data = array;
var newData = [];
var formattedData = [];
for (var i in data) {
var row = data[i];
var duplicate = false;
for (var j in newData) {
if (row === newData[j] && row === newData[j]) {
duplicate = true;
}
}
if (!duplicate) {
newData.push(row);
}
}
newData.forEach(function(i){
formattedData.push([i]);
});
return formattedData;
}
Sample Result:
Sample Sheet
When spreadsheet gets updated with new data

PHP Spreadsheet: After saving data to a new worksheet, the data of the previous worksheets are deleted

I am creating a script to save CSV data into an excel document, but in different worksheets, I mean, every CSV doc will go into a new worksheet, but after saving data to a new worksheet the previous data that are in the other worksheets are deleted. This is my code
<?php
require 'vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$spreadsheet = new Spreadsheet();
$spreadsheet2 = new Spreadsheet();
$reader = new PhpOffice\PhpSpreadsheet\Reader\Xlsx();
$spreadsheet = $reader->load('test.xlsx');
$numSheets = $spreadsheet -> getSheetCount();
$reader2 = new PhpOffice\PhpSpreadsheet\Reader\Csv();
/* Set CSV parsing options */
$reader2->setDelimiter(',');
$reader2->setEnclosure('"');
$reader2->setSheetIndex($numSheets);
echo $numSheets;
/* Load a CSV file and save as a XLS */
$spreadsheet2 = $reader2->load('testcsv.csv');
$writer = new Xlsx($spreadsheet2);
$writer->save('test.xlsx');
$spreadsheet->disconnectWorksheets();
unset($spreadsheet);
?>
With this only the last worksheet have data
enter image description here
I want to emphasize that I have no errors but I am not achieving what I want to do
The problem is that you use
$numSheets = $spreadsheet -> getSheetCount();
but you must count your sheet numbers and add a new sheet in your file.
I would suggest you use a loop.
$numSheets = $spreadsheet -> getSheetCount();
foreach($csvs as $csv){
// Create a new worksheet called "My Data"
$myWorkSheet = new \PhpOffice\PhpSpreadsheet\Worksheet\Worksheet($spreadsheet, 'My Data');
// Attach the "My Data" worksheet as the first worksheet in the Spreadsheet object
$spreadsheet->addSheet($myWorkSheet, $numSheets);
$numSheets++;
}
More information here

How to generate Excel form EPPluse which has group column header

I want to generate excel sheet from EPPluse which has group column header like below picture.Then How to build DataTable which handle this situation. please help me to get it done easily.
Thanks in advance
You want to use the Merge property on the ExcelRange object.
Here's an example:
using (var pck = new ExcelPackage(new FileInfo(#"c:\temp\Book1.xlsx")))
{
var ws = pck.Workbook.Worksheets["Sheet1"] ?? pck.Workbook.Worksheets.Add("Sheet1");
var rng = ws.Cells["BO1:BQ1"];
rng.Merge = true;
rng.Value = "Answer for Att 3";
pck.Save();
}
You can use this code to write your group headers, then use ExcelRange's LoadFromDataTable() method to write your DataTable directly to the worksheet starting from cell A2

Concatenate certain rows into a cell ignoring duplicates

I have a google form and I would like to sort it's responses in a separate sheet on google sheets. The results of the form look sort of like this.
Id Job
1 Shelving, Sorting
2 Sorting
1 Cleaning, Shelving
3 Customer Service
2 Shelving, Sorting
which I would like to format into
Id Jobs
1 Cleaning, Shelving, Sorting
2 Shelving, Sorting
3 Customer Service
Is there a formula I can use to accomplish this, noting that it ignores duplicates and groups the different ids? Ordering of the jobs does not matter.
Working example here.
The code is like:
=unique(transpose(split(join(", ",filter(B1:B10,A1:A10=1)),", ")))
where
filter(B1:B10,A1:A10=1) gives you all the B values where A = 1
join(",", filter(...)) joins the list with the ", " separator (e.g. "apple, orange" and "kiwi" becomes "apple, orange, kiwi"
split(join(...)) splits the list into an array (e.g. back to [apple, orange, kiwi]
transpose(split(...)) converts the horizontal list to vertical list
unique(transpose(...)) gives you the unique values (unique() only works with vertical list)
After this, you need to transpose then join the list
Note you must keep the separator consistent (e.g. always "," or ", ")
This is Apps Script code instead of a function. To use it, you will need to use the Tools menu, and open the script editor. Then select the function name from the drop down list, and then click the "Run" button.
To use this code, you need to have a source and a destination sheet. You will need to change the sheet names in the code to your sheet names. In this code, the source sheet is named 'Data'. You will need to change that to the name of your source sheet. In this code, the destination sheet is named 'Output', and is at the bottom of the code. This code gets data starting in row two, and writes the output data starting in row two. I tested it with your values and it works.
function concatCellData() {
var ss = SpreadsheetApp.getActiveSpreadsheet();
var sh = ss.getSheetByName('Data');
var colOneData = sh.getRange(2, 1, sh.getLastRow()-1, 1).getValues();
var colTwoData = sh.getRange(2, 2, sh.getLastRow()-1, 1).getValues();
var newData = [],
newDataColOne = [],
colOneValue,
existInNewData = false,
colB_One,
colB_Two,
dataPosition,
thisValue,
combinedArrays = [],
arrayTemp = [];
for (var i=0;i<colOneData.length;i+=1) {
colOneValue = colOneData[i][0];
dataPosition = newDataColOne.indexOf(colOneValue);
existInNewData = dataPosition !== -1;
if (!existInNewData) {//If it doesn't exist in the new data, just write the values
newDataColOne.push(colOneValue);
newData.push([colOneValue, colTwoData[i][0]]);
continue;
};
colB_One = [];
colB_Two = [];
combinedArrays = []
arrayTemp = [];
colB_One = colTwoData[i][0].split(",");
colB_Two = newData[dataPosition][1];
colB_Two = colB_Two.split(",");
var combinedArrays = colB_One.concat(colB_Two);
//Get unique values
for (var j=0;j<combinedArrays.length;j+=1) {
thisValue = combinedArrays[j].trim();
if (arrayTemp.indexOf(thisValue) === -1) {
arrayTemp.push(thisValue);
};
};
newData[dataPosition] = [colOneValue, arrayTemp.toString()]; //Overwrite existing data
};
ss.getSheetByName('Output').getRange(2, 1, newData.length, newData[0].length).setValues(newData);
};

PowerQuery multiple files and add column

I have the inline PowerQuery to automate my weekly reporting. Since I am new to power query I followed up this tutorial and try to add a custom column so I can use it to see week over week improvements, the thing is that the column that is added is not named "Week" but instead it is called the name of the file. From this webpage the second parameter is column name. I do not find why column name is filename instead of the name "week".
let ExcelFile = (FilePath, FileName) =>
let
Source = Folder.Files(FilePath),
File = Source{[#"Folder Path"=FilePath,Name=FileName]}[Content],
ImportedExcel = Excel.Workbook(File),
Sheet1 = ImportedExcel{[Name="Page1_1"]}[Data],
TableWithWeek = Table.AddColumn(Sheet1,"Week", each FileName),
TableWithoutHeader = Table.Skip(TableWithWeek,3),
FirstRowAsHeader = Table.PromoteHeaders(TableWithoutHeader)
in
FirstRowAsHeader
in
ExcelFile
This call:
FirstRowAsHeader = Table.PromoteHeaders(TableWithoutHeader)
will replace the column names you have with the values from the first row. Since the first value under the column "Week" is the filename, then your table will now use that filename as the column name.
You can fix this by adding the custom column after you use PromoteHeaders:
let ExcelFile = (FilePath, FileName) =>
let
Source = Folder.Files(FilePath),
File = Source{[#"Folder Path"=FilePath,Name=FileName]}[Content],
ImportedExcel = Excel.Workbook(File),
Sheet1 = ImportedExcel{[Name="Page1_1"]}[Data],
TableWithoutHeader = Table.Skip(Sheet1, 3),
FirstRowAsHeader = Table.PromoteHeaders(TableWithoutHeader),
TableWithWeek = Table.AddColumn(FirstRowAsHeader,"Week", each FileName),
in
TableWithWeek
in
ExcelFile

Resources