Skip to content

Instantly share code, notes, and snippets.

@WhiteBearSpirit
Last active April 12, 2025 19:01
Show Gist options
  • Save WhiteBearSpirit/94045ead951a27c06a0fe69d9c1980fb to your computer and use it in GitHub Desktop.
Save WhiteBearSpirit/94045ead951a27c06a0fe69d9c1980fb to your computer and use it in GitHub Desktop.
<html>
<head>
<title>Money cat</title>
</head>
<body>
<div style="display: inline-block;">
<textarea id="in" name="in" rows="40" cols="100"></textarea>
<textarea id="out" name="out" rows="40" cols="100"></textarea>
</div>
<div>
<button onclick="process();">Categorize</button>
</div>
</body>
</html>
<script type="text/javascript">
function process() {
const values = document.getElementById('in').value.split('\n');
var actor = null;
var trataList = Array();
var creditList = Array();
for (let i = 0; i < values.length; i++) {
const line = values[i];
if (!line) { continue; }
const actorMatch = line.match(/(\p{L}+), \[\d\d\.\d\d\.\d{4} \d\d:\d\d\]/u);
if (actorMatch) {
actor = actorMatch[1];
continue;
}
const match = line.match(/^-?(\d+)\s+(.+)/u);
if (match) {
const trata = { actor: actor, cost: parseInt(match[1]), good: match[2].trim() };
trataList.push(trata);
}
else {
const creditMatch = line.match(/^\+\s?(\d+)\s+(.+)/u);
if (creditMatch) {
creditList.push({ actor: actor, data: line.trim() });
}
}
}
const groupedDebit = groupBy(trataList, "actor");
document.getElementById("out").value = "";
for (let [key, value] of groupedDebit) {
const outLines = value.map(t => t.cost + "\t" + categorizeSingle(t.good) + "\t" + t.good);
document.getElementById("out").value = document.getElementById("out").value + key + "\n" + outLines.join("\n") + "\n\n";
}
const groupedCredit = groupBy(creditList, "actor");
for (let [key, value] of groupedCredit) {
const outLines = value.map(t => t.data.replace(/\+\s*/, "").replace(/\s+/, "\t"));
document.getElementById("out").value = document.getElementById("out").value + "Приход " + key + ":\n" + outLines.join("\n") + "\n\n";
}
}
function categorizeSingle(good) {
if (!good) { return "ХЗ"; }
const keys = Object.keys(catalog);
const match = keys.find(s => good.toLowerCase().startsWith(s.toLowerCase()));
const catalogued = catalog[match];
if (!catalogued) { return "ХЗ: " + good; }
return catalogued;
}
// Категории:
// Еда
// Личное
// Здоровье
// Животные
// Хозбыт
// Строй
// Жильё
// Личное
// Телеком
// Транспорт
// Запас/Кредит
const catalog = {
"зсд": "Транспорт",
"самокат": "Транспорт",
"сомокат": "Транспорт",
"кш": "Транспорт",
"еда": "Еда",
"продукты": "Еда",
"человекоеда": "Еда",
"морожен": "Еда",
"кафе": "Еда",
"тоже еда": "Еда",
"бензин": "Транспорт",
"мойка": "Транспорт",
"электричка": "Транспорт",
"электричество": "Жильё",
"Жильё": "Жильё",
"квартплата": "Жильё",
"коммуналка": "Жильё",
"квартира": "Жильё",
"домик": "Жильё",
"гостиница": "Жильё",
"хата": "Жильё",
"кусок кварт": "Жильё",
"спотифай": "Личное",
"хоз": "Хозбыт",
"стакан": "Хозбыт",
"кружка": "Хозбыт",
"строй": "Строй",
"др": "Личное",
"открытки": "Личное",
"кино": "Личное",
"сувенир": "Личное",
"звероеда": "Животные",
"животные": "Животные",
"еда котам": "Животные",
"птицам": "Животные",
"наполнитель котам": "Животные",
"котоеда": "Животные",
"котокорм": "Животные",
"подарки": "Личное",
"подарок": "Личное",
"музеум": "Личное",
"авто": "Транспорт",
"одлп": "Личное",
"фольга": "Хозбыт",
"цветочег": "Личное",
"личное": "Личное",
"штаны": "Личное",
"ресторан": "Личное",
"лента еда": "Еда",
"чай": "Еда",
"вода": "Еда",
"шаверма": "Еда",
"арбу": "Еда",
"овощи": "Еда",
"фрукт": "Еда",
"плов": "Еда",
"билет на эл": "Транспорт",
"билет на по": "Транспорт",
"транспондер": "Транспорт",
"парковка": "Транспорт",
"кофе": "Еда",
"букет": "Личное",
"вет": "Животные",
"такси": "Транспорт",
"транспорт": "Транспорт",
"платные дороги": "Транспорт",
"сомокот": "Транспорт",
"интенсив": "Личное",
"йота": "Телеком",
"моб ": "Телеком",
"телеком": "Телеком",
"мобильный": "Телеком",
"мтс": "Телеком",
"мегафон": "Телеком",
"интернет": "Телеком",
"платеж по кредит": "Запас/Кредит",
"кредит": "Запас/Кредит",
"запас": "Запас/Кредит",
"торт": "Еда",
"одежда": "Личное",
"аптека": "Здоровье",
"здоровье": "Здоровье",
"мелатонин": "Здоровье",
"психо": "Здоровье",
"гло": "Личное",
"стики": "Личное",
"вейп": "Личное",
"птен": "Животные",
"билайн": "Телеком",
"кот": "Животные",
"котам": "Животные",
"птиц": "Животные",
"ключ": "Жильё",
"Сказк": "личное",
"благо": "личное",
"лично": "личное",
"бензак": "транспорт"
};
function groupBy(items, key) {
const map = new Map();
items.forEach((item) => {
const keyValue = item[key];
const currArr = map.has(keyValue) ? map.get(keyValue) : [];
currArr.push(item);
map.set(keyValue, currArr);
});
return map;
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment