Volond Apps
222 subscribers
216 photos
28 videos
22 files
994 links
Программирование для души и от лени
Добро пожаловать! У нас есть отличное сообщество любителей Excel и VBA, Google Sheet и Google Apps Script, а также всех тех, кто готов работать с этим программным обеспечением. Присоединяйтесь к нам, чтобы задавать и от
Download Telegram
Боже! Как давно я это искал
После "допиливания" надеюсь поможет мне навести порядок в моих скриптах

Получение отформатированных сценариев без комментариев в проекте с использованием скрипта Google Apps

P.S.
1. Хотя почему-то комментарии не удалил при тестовом прогоне хотя это даже к лучшему.
2. Стоит посмотреть как среагирует на среду разработки V.8
Телеграм Бот на Google Script
Telegram GAS BOT
Forwarded from Хабр
#snippet Unpivot a pivot table of any size

/**
* Unpivot a pivot table of any size.
*
* @param {A1:D30} data The pivot table.
* @param {1} fixColumns Number of columns, after which pivoted values begin. Default 1.
* @param {1} fixRows Number of rows (1 or 2), after which pivoted values begin. Default 1.
* @param {"city"} titlePivot The title of horizontal pivot values. Default "column".
* @param {"distance"[,...]} titleValue The title of pivot table values. Default "value".
* @return The unpivoted table
* @customfunction
*/
function unpivot(data,fixColumns,fixRows,titlePivot,titleValue) {
var fixColumns = fixColumns || 1; // how many columns are fixed
var fixRows = fixRows || 1; // how many rows are fixed
var titlePivot = titlePivot || 'column';
var titleValue = titleValue || 'value';
var ret=[],i,j,row,uniqueCols=1;

// we handle only 2 dimension arrays
if (!Array.isArray(data) || data.length < fixRows || !Array.isArray(data[0]) || data[0].length < fixColumns)
throw new Error('no data');
// we handle max 2 fixed rows
if (fixRows > 2)
throw new Error('max 2 fixed rows are allowed');

// fill empty cells in the first row with value set last in previous columns (for 2 fixed rows)
var tmp = '';
for (j=0;j<data[0].length;j++)
if (data[0][j] != '')
tmp = data[0][j];
else
data[0][j] = tmp;

// for 2 fixed rows calculate unique column number
if (fixRows == 2)
{
uniqueCols = 0;
tmp = {};
for (j=fixColumns;j<data[1].length;j++)
if (typeof tmp[ data[1][j] ] == 'undefined')
{
tmp[ data[1][j] ] = 1;
uniqueCols++;
}
}

// return first row: fix column titles + pivoted values column title + values column title(s)
row = [];
for (j=0;j<fixColumns;j++) row.push(fixRows == 2 ? data[0][j]||data[1][j] : data[0][j]); // for 2 fixed rows we try to find the title in row 1 and row 2
for (j=3;j<arguments.length;j++) row.push(arguments[j]);
ret.push(row);

// processing rows (skipping the fixed columns, then dedicating a new row for each pivoted value)
for (i=fixRows;i<data.length && data[i].length > 0 && data[i][0];i++)
{
row = [];
for (j=0;j<fixColumns && j<data[i].length;j++)
row.push(data[i][j]);
for (j=fixColumns;j<data[i].length;j+=uniqueCols)
ret.push(
row.concat([data[0][j]]) // the first row title value
.concat(data[i].slice(j,j+uniqueCols)) // pivoted values
);
}

return ret;
}
Класс для управления Properties
#snippet #GAS
/**
* Класс для управления Properties
* DocumentProperties or ScriptProperties or UserProperties
*
* Creates an instance of Props.
* @param {string} prop
* @memberof Props
* @constructor
* https://developers.google.com/apps-script/reference/properties
* @example
* const testProps=()=>{
* const scrProp=new Props("ScriptProperties");
* scrProp.set("v","1")
* concole.log(scrProp.get("v"))
* }
* @return {} Class Properties
*/
class Props {
constructor(prop) {
this[prop] = PropertiesService['get'+prop]();
this.type=prop
return this;
}

get(name) {
return this[this.type].getProperty(name);
}

getProperties(name) {
return this[this.type].getProperties();
}
type(prop) {
return this.type;
}
set(name, value) {
return this[this.type].setProperty(name, value);
}

forget(name) {
return this[this.type].deleteProperty(name);
}

getKeys() {
return this[this.type].getKeys();
}
has(callback,name) {
return this[this.type].getKeys().some(callback,element);
}

deleteAllProperties(){
this[this.type].deleteAllProperties();
}

setProperties(properties){
this[this.type].setProperties(properties);
}
setProperties(properties, deleteAllOthers){
this[this.type].setProperties(properties, deleteAllOthers);
}
}
Как получить имя запущенной функции в JavaScript?
#snippet
const es6=()=>{console.log(getMyName())}

function getMyName() {
var e = new Error('dummy');
var stack = e.stack
.split('\n')[2]
// " at functionName ( ..." => "functionName"
.replace(/^\s+at\s+(.+?)\s.+/g, '$1' );
return stack
}

Заполнить пустые ячейки данными из предыдущих непустых
#snippet
/**
* Заполнить пустые ячейки данными из предыдущих непустых
* тут формулами https://contributor.pw/post/fill-blank-cells-with-data-from-above-cell/
* но для одного столбца
* @param {Object} obj {arr,columnIndexStart,columnIndexStart}
* @param {Array[[]]} obj.arr - Индекс столбца с которого начинается преобразование
* @param {Number} obj.columnIndexStart - Индекс столбца с которого начинается преобразование
* @param {Number} obj.columnIndexEnd - Индекс столбца перед которого закончится преобразование(В выборку не попадает)
* @returns {Array} Преобразованный массив
* @example
* input Array
* let arr=[
* [1,2,3],
* [,,5],
* [8,9,10],
* [,11,12]
* ]
* return Array
* [ [ 1, 2, 3 ],
* [ 1, 2, 5 ],
* [ 8, 9, 10 ],
* [ 8, 11, 12 ]
* ]
*
*
*
*/
const fillData_ = ({ arr, columnIndexStart = 0, columnIndexEnd }) => {
/*
// tmp.forEach((item,j)=>{ //!!!!!forEach НЕ ВИДИТ undefined элементы

*/


let arrReptValue = arr[0].slice(columnIndexStart, columnIndexEnd)
arr.forEach((row, i, data) => {

let tmp = row.slice(columnIndexStart, columnIndexEnd)

for (j = 0; j < tmp.length; j++) {
if (isEmpty(tmp[j])) {
arr[i][j] = arrReptValue[j]
} else {
arrReptValue[j] = arr[i][j]
}
}
})
return arr
}
const isEmpty = (value) => {
return value === undefined || value === null || value === "";
}
Как удалить пустые столбцы в 2D Array в JS
#snippet #JS #GAS

var csvData = [["", "2", ""], ["", "3", ""], ["", "4", ""], ["1", "3", ""]],
columns = csvData.reduce(
(r, a) => (a.forEach((v, i) => r[i] = r[i] || v), r),
csvData[0].map(_ => false)
);

csvData = csvData.map(a => a.filter((_, i) => columns[i]));

console.log(csvData);
Текущее время смайликами
=join("";{VLOOKUP((HOUR(NOW())-mod(HOUR(NOW());10))/10;{SEQUENCE(10;1;0)\{"0️⃣";"1️⃣";"2️⃣";"3️⃣";"4️⃣";"5️⃣";"6️⃣";"7️⃣";"8️⃣";"9️⃣"}};2)&VLOOKUP(mod(HOUR(NOW());10);{SEQUENCE(10;1;0)\{"0️⃣";"1️⃣";"2️⃣";"3️⃣";"4️⃣";"5️⃣";"6️⃣";"7️⃣";"8️⃣";"9️⃣"}};2)\VLOOKUP((MINUTE(NOW())-mod(MINUTE(NOW());10))/10;{SEQUENCE(10;1;0)\{"0️⃣";"1️⃣";"2️⃣";"3️⃣";"4️⃣";"5️⃣";"6️⃣";"7️⃣";"8️⃣";"9️⃣"}};2)&VLOOKUP(mod(MINUTE(NOW());10);{SEQUENCE(10;1;0)\{"0️⃣";"1️⃣";"2️⃣";"3️⃣";"4️⃣";"5️⃣";"6️⃣";"7️⃣";"8️⃣";"9️⃣"}};2)\VLOOKUP((SECOND(NOW())-mod(SECOND(NOW());10))/10;{SEQUENCE(10;1;0)\{"0️⃣";"1️⃣";"2️⃣";"3️⃣";"4️⃣";"5️⃣";"6️⃣";"7️⃣";"8️⃣";"9️⃣"}};2)&VLOOKUP(mod(SECOND(NOW());10);{SEQUENCE(10;1;0)\{"0️⃣";"1️⃣";"2️⃣";"3️⃣";"4️⃣";"5️⃣";"6️⃣";"7️⃣";"8️⃣";"9️⃣"}};2)})
/
* @OnlyCurrentDoc
* EN: Restricts script access to the current sheet only.
* RU: Ограничивает доступ скрипта только к текущему листу.
*/

/* exported REGEXMATCHS */
/* globals sorosWrapper_ */

/
* 𝗘𝗡: Returns an array of matches.
*
* 𝗥𝗨: Возвращает массив совпадений.
*
* 𝗩𝗲𝗿𝘀𝗶𝗼𝗻: 1.0
*
* 𝗔𝘂𝘁𝗵𝗼𝗿: Stoyanov Maksim (stomaks)
* 𝗦𝗶𝘁𝗲: stomaks.me
* 𝗕𝗹𝗼𝗴: G-Apps-Script.COM
*
* @param {string} text
* 𝗘𝗡: The text to check.
*
* 𝗥𝗨: Текст, который необходимо проверить.
*
* @param {string} regexp
* 𝗘𝗡: The regular expression to find in the text.
*
* 𝗥𝗨: Регулярное выражение, которое нужно найти в тексте.
*
* @param {number} type
* 𝗘𝗡: Type of response (
* 0 - substring;
* 1 - index of the first character of the substring;
* 2 - substring length;
* 3 - index of the last character of the substring).
*
* 𝗥𝗨: Тип ответа (
* 0 - подстрока;
* 1 - индекс первого символа подстроки;
* 2 - длина подстроки;
* 3 - индекс последнего символа подстроки).
*
* @return {array}
* 𝗘𝗡: An array of matches.
*
* 𝗥𝗨: Массив совпадений.
*
* @customfunction
*/
function REGEXMATCHS ( text, regexp, type ) {
var response = [];

text = String(text);

var flags = "g";

if ( /^\(\?i\)/.test(regexp) ) {
regexp = regexp.replace(/^\(\?i\)/, "");
flags += "i";
}

var subs = text.match( new RegExp(regexp, flags) );

if ( !subs ) return null;

for ( var cursor = subs.index, l = subs.length, i = 0; i < l; i += 1 ) {
var index = cursor;

if ( i+1 !== l && subs[i] !== subs[i+1] ) {

nextIndex = text.indexOf(subs[i+1], cursor);

while ( true ) {

currentIndex = text.indexOf(subs[i], index);

if ( currentIndex !== -1 && currentIndex <= nextIndex ) {
index = currentIndex + 1;
} else break;
}

index -= 1;
} else {
index = text.indexOf(subs[i], cursor);
}
cursor = index + subs[i].length;

switch ( type ) {
case 1:
response.push( index );
break;

case 2:
response.push( subs[i].length );
break;

case 3:
response.push( index + subs[i].length );
break;

case 0:
default:
response.push( subs[i] );
break;
}
}

return response;
}
/**
* Как разбить массив на заданные куски
* splitEvery(3, [1, 2, 3, 4, 5, 6, 7]); //=> [[1, 2, 3], [4, 5, 6], [7]]
* Number → [a] → [[a]]
* @param {*} n
* @param {*} row
* @returns
*/
function splitEvery(n, row) {
return (row) => {
var result = [];
var idx = 0;
while (idx < row.length) {
result.push(row.slice(idx, idx += n));
}
return result
}
}

#snippet
Как разбить 2D масив на заданные куски
/**
* Как разбить 2D масив на заданные куски
* Number → [a] → [[a],[b]]
* @param {*} n
* @param {*} range
* @returns
*/
function splitEveryMap(n, range) {
const sp = splitEvery(n)
return range.map(sp).flat(1)
}
#snippet #JS
Вытягиваем код Вашего проекта в таблицу

/**
* Returns an array of function names and their code
* In the current project
* Arrow functions do not fall into this array
* ....................................................
* Возвращает массив имен функций и их кода
* В текущем проекте
* Функции-стрелки в этот массив не попадают
*
* @return {Array}
* @customfunction
*/
function getFunction(){
const nameFn=Object.keys(this)
return (nameFn.map(el=>[el,this[el]]))
}

#snippet #GAS
О сортировке замолвите слово
function compareNumbers(a, b) {
if (a === b) return 0;
if (a > b) return 1;
/* else */
return -1;
}

function compareNumbers1(a, b) {
if (+a === +b) return 0;
if (+a > +b) return 1;
/* else */
return -1;
}
let nums = ["7", "3", "1", "5", "8", "11", "6", "4", "2"];
nums.sort()
console.log(nums)
nums.sort(compareNumbers);
console.log(nums);
/* 〕[
'1', '11', '2',
'3', '4', '5',
'6', '7', '8'
]
*/
nums.sort(compareNumbers1);
console.log(nums);
/*
[
'1', '2', '3',
'4', '5', '6',
'7', '8', '11'
]
*/