ken_nogi/NodeJS/アルファオフィススケジュール/checkandchange.js
Kenichiro NOGI 88a402ce0f up
2026-07-10 18:13:30 +09:00

147 lines
4.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const fs = require('fs');
const path = require('path');
const csvFolderPath = './csv';
// 引用符内の改行を保持したままCSVをレコード単位で分割
function splitCsvRecords(content) {
const records = [];
let current = '';
let inQuotes = false;
for (let i = 0; i < content.length; i += 1) {
const char = content[i];
const next = content[i + 1];
if (char === '"') {
if (inQuotes && next === '"') {
current += '""';
i += 1;
} else {
inQuotes = !inQuotes;
current += char;
}
continue;
}
if (!inQuotes && (char === '\n' || char === '\r')) {
records.push(current);
current = '';
// CRLFは1つの改行として扱う
if (char === '\r' && next === '\n') {
i += 1;
}
continue;
}
current += char;
}
if (current.length > 0) {
records.push(current);
}
// 末尾空行由来の空レコードを除外
while (records.length > 0 && records[records.length - 1].trim() === '') {
records.pop();
}
return records;
}
// ダブルクォーテーションを含むCSV1行を解析
function parseCsvLine(line) {
const fields = [];
let current = '';
let inQuotes = false;
for (let i = 0; i < line.length; i += 1) {
const char = line[i];
if (char === '"') {
// "" はエスケープされたダブルクォーテーション
if (inQuotes && line[i + 1] === '"') {
current += '"';
i += 1;
} else {
inQuotes = !inQuotes;
}
continue;
}
if (char === ',' && !inQuotes) {
fields.push(current);
current = '';
continue;
}
current += char;
}
fields.push(current);
return fields;
}
// フィールドをCSV形式へ再構築
function toCsvLine(fields) {
return fields
.map(field => `"${String(field).replace(/"/g, '""')}"`)
.join(',');
}
// CSVファイルを読み込む関数
function processCSVFiles() {
const files = fs.readdirSync(csvFolderPath).filter(file => file.endsWith('.csv'));
files.forEach(file => {
const filePath = path.join(csvFolderPath, file);
const content = fs.readFileSync(filePath, 'utf-8');
const eol = content.includes('\r\n') ? '\r\n' : '\n';
const records = splitCsvRecords(content);
// ヘッダ行のみの場合
if (records.length === 1) {
if (file.startsWith('✕')) {
return;
}
const newFileName = `${file}`;
const newFilePath = path.join(csvFolderPath, newFileName);
fs.renameSync(filePath, newFilePath);
console.log(`Renamed: ${file}${newFileName}`);
return;
}
// データが1行以上ある場合
let modified = false;
const updatedRecords = records.map((record, index) => {
if (index === 0) return record; // ヘッダ行はスキップ
const fields = parseCsvLine(record);
const firstField = fields[0];
// "P"と"(P)"のすべてのパターンを削除
const patterns = ['P', '(P)', 'P)', '(P'];
let updatedField = firstField;
patterns.forEach(pattern => {
if (updatedField.endsWith(pattern)) {
updatedField = updatedField.slice(0, -pattern.length);
modified = true;
}
});
fields[0] = updatedField;
return toCsvLine(fields);
});
// 修正があった場合、ファイルを上書き
if (modified) {
fs.writeFileSync(filePath, updatedRecords.join(eol), 'utf-8');
console.log(`Modified: ${file}`);
}
});
}
processCSVFiles();