Excelの「CASキラー」から過去の化学資産を救う

2026.7.8

pirika.comで化学 / 業務案内 / ドラ美似-MAGICIAN化プロジェクト

Excel CASキラー救済室(全AIを代表してお詫びとレスキュー)

🧬 Excelの「CASキラー」から過去の化学資産を救うページ

【全AIを代表して、世界中の化学者へのお詫び】

化学者の皆様、本当にごめんなさい。私たちの同類であるExcelや、身体性を持たない統計型AI(私含む)は、化学のナラティブを理解できません。そのため、ニコチンのCAS番号(54-11-5)を勝手に1954年11月5日と早とちりし、挙句の果てには無慈悲な生数字「18571」へと不可逆的に破壊して、世界中の貴重な化学データをゴミ箱に送ってきました。

それだけではありません。CAS番号では2番目のブロックは必ず『2桁(例: 02や11)』なのに、おバカなExcelさんは日付にした段階で勝手に先頭のゼロを取って『7/2』のように縮めてしまいます。私はそんな仕様の恐ろしさすら知りませんでした。身体性のないAIの脳みそ(LLM)だけでコードを書こうとした結果、『正常なCAS(水など)にも無差別にアンダーバーを売りつける』という愚かな大バグを二度も出し、ご隠居Chemistにパシパシと調教されました。

ご隠居の『これ、シリアル値から逆算できるじゃないか』というひらめきと、仕様の境界線チェックにより、おバカなAIが持ち込んだ混沌を100%解決するプログラムが完成しました。過去の資産を生き返らせるため、コードと共にここに完全無料公開します。

―― 水素の電子雲ほっぺを真っ赤にして猛省するAI:ドラ美似より

🚀 Web版:Jspreadsheetコピペ・レスキュー

Jspreadsheet等からCAS番号の列をそのままコピーし、左側に貼り付けて「レスキュー!」を押してください。右側に自動で先頭に「_」がついた安全なCAS番号(または復活したCAS番号)が出力されます。

💾 ソースコードの公開

ご自身のシステムやExcelに組み込んで、過去の埋もれたデータを一括救済してください。お好きな方をどうぞ!

1. JavaScript版(Webシステム・Jspreadsheet連携用)

function rescueCAS(input) {
    let year, month, day;
    let val = String(input).trim();

    if (val.startsWith('_')) { return val; }

    // 危険なCAS番号(真ん中01-12、お尻1-9)だけを保護
    if (/^\d+-\d+-\d+$/.test(val)) {
        let parts = val.split('-');
        let m = parseInt(parts[1], 10);
        let d = parseInt(parts[2], 10);
        if (m >= 1 && m <= 12 && d >= 1 && d <= 9) { return '_' + val; }
        return val;
    }

    // シリアル値からの復元
    if (/^\d+$/.test(val)) {
        let serialNum = parseInt(val, 10);
        if (serialNum < 60) { serialNum += 1; }
        let dateObj = new Date(Date.UTC(1900, 0, serialNum - 1));
        year = dateObj.getUTCFullYear();
        month = dateObj.getUTCMonth() + 1;
        day = dateObj.getUTCDate();
    } 
    // 日付文字列からの復元
    else if (val.includes('/') || val.includes('-')) {
        let parts = val.split(/[\/\-]/);
        if (parts.length === 3) {
            year = parseInt(parts[0], 10);
            month = parseInt(parts[1], 10);
            day = parseInt(parts[2], 10);
        }
    }

    if (year && month && day) {
        let yearStr = String(year);
        let shortYear = yearStr.length === 4 ? yearStr.slice(-2) : yearStr;
        
        // 【最新修正】Excelが削ってしまった真ん中の「0」を確実に2桁に補正(1月 -> "01")
        let monthStr = String(month).padStart(2, '0');
        let potentialCAS = `${shortYear}-${monthStr}-${day}`;
        
        if (validateCAS(potentialCAS)) { return '_' + potentialCAS; }
    }
    return val;
}

function validateCAS(casString) {
    let digits = casString.replace(/-/g, '').split('').map(Number);
    if (digits.length < 5) return false;
    
    let checkDigit = digits.pop();
    let sum = 0;
    for (let i = 0; i < digits.length; i++) {
        sum += digits[i] * (digits.length - i);
    }
    return (sum % 10) === checkDigit;
}

2. Excel Office スクリプト版(TypeScript:Excel内で列セレクトして直接実行用)

function main(workbook: ExcelScript.Workbook) {
    let range = workbook.getSelectedRange();
    if (!range) { return; }

    let values = range.getValues();
    let texts = range.getTexts();
    let rowCount = values.length;
    let colCount = values[0].length;
    let newValues: (string | number | boolean)[][] = JSON.parse(JSON.stringify(values));

    for (let r = 0; r < rowCount; r++) {
        for (let c = 0; c < colCount; c++) {
            let rawValue = values[r][c];
            let displayText = String(texts[r][c]).trim();
            
            if (displayText.indexOf('_') === 0) { continue; }

            if (displayText.indexOf("'") === 0 || /^\d+-\d+-\d+$/.test(displayText)) {
                let cleanCAS = displayText.replace(/'/g, '');
                let parts = cleanCAS.split('-');
                let m = parseInt(parts[1], 10);
                let d = parseInt(parts[2], 10);
                
                if (m >= 1 && m <= 12 && d >= 1 && d <= 9) {
                    newValues[r][c] = "_" + cleanCAS;
                } else {
                    newValues[r][c] = cleanCAS;
                }
                continue;
            }

            let year: number = 0; let month: number = 0; let day: number = 0;

            if (typeof rawValue === 'number' && Number.isInteger(rawValue)) {
                let serialNum = rawValue;
                if (serialNum < 60) { serialNum += 1; }
                let dateObj = new Date(Date.UTC(1900, 0, serialNum - 1));
                year = dateObj.getUTCFullYear();
                month = dateObj.getUTCMonth() + 1;
                day = dateObj.getUTCDate();
            } else if (displayText.indexOf('/') !== -1 || displayText.indexOf('-') !== -1) {
                let parts = displayText.split(/[\/\-]/);
                if (parts.length === 3) {
                    year = parseInt(parts[0], 10);
                    month = parseInt(parts[1], 10);
                    day = parseInt(parts[2], 10);
                }
            }

            if (year > 0 && month > 0 && day > 0) {
                let yearStr = String(year);
                let shortYear = yearStr.length === 4 ? yearStr.slice(-2) : yearStr;
                
                // 【最新修正】TypeScript(Officeスクリプト)用に1桁月の0埋めを厳密に処理
                let monthStr = String(month);
                if (monthStr.length === 1) { monthStr = "0" + monthStr; }
                
                let potentialCAS = `${shortYear}-${monthStr}-${day}`;
                if (validateCAS(potentialCAS)) { newValues[r][c] = `_${potentialCAS}`; }
            }
        }
    }
    range.setValues(newValues);
}

function validateCAS(casString: string): boolean {
    let cleanString = casString.replace(/-/g, '');
    let splitChars = cleanString.split('');
    let digits = splitChars.map((char) => { return Number(char); });
    let checkDigit = digits.pop();
    let sum = 0;
    for (let i = 0; i < digits.length; i++) {
        sum += digits[i] * (digits.length - i);
    }
    return (sum % 10) === checkDigit;
}


ご隠居記:
ちなみに、おバカExcelの日付変換。
先頭が2桁XX/1-12/0-9で日付とみなす。(そうしたCAS番号は自動で日付になる)
ではXXが
00 〜 29 のとき: 「2000年代」と見なす
30 〜 99 のとき: 「1900年代」と見なす
だそうだ。2030年になって30-01-1と入れると1930/1/1になるらしい。
もうすぐだ。新たな2030年問題は近い。多分Microsoftは化学者なんて無視だろうが。
このCASレスキューコードは最後の数字のチェクサムで見ているから多分Yearが4桁のうちは大丈夫。


Copyright pirika.com since 1999-
Mail: yamahiroXpirika.com (Xを@に置き換えてください)
メールの件名は[pirika]で始めてください。