{"id":40622556,"url":"https://github.com/lsyueh/get-the-picture","last_synced_at":"2026-03-03T20:01:05.935Z","repository":{"id":331432067,"uuid":"1125029748","full_name":"LsYueh/Get-The-Picture","owner":"LsYueh","description":"為現代 .NET 應用程式提供 COBOL Copybook 支援","archived":false,"fork":false,"pushed_at":"2026-02-08T16:48:39.000Z","size":1121,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-02-08T22:34:07.684Z","etag":null,"topics":["cobol","cobol-conversion","cobol-copybook","cobol-pic","csharp","csharp-library","data-exchange","data-export","deserialization","endian","endianness","endianswap","isam","parser","serialization"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LsYueh.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-30T03:11:25.000Z","updated_at":"2026-02-07T02:50:25.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/LsYueh/Get-The-Picture","commit_stats":null,"previous_names":["lsyueh/get-the-picture"],"tags_count":23,"template":false,"template_full_name":null,"purl":"pkg:github/LsYueh/Get-The-Picture","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LsYueh%2FGet-The-Picture","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LsYueh%2FGet-The-Picture/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LsYueh%2FGet-The-Picture/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LsYueh%2FGet-The-Picture/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LsYueh","download_url":"https://codeload.github.com/LsYueh/Get-The-Picture/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LsYueh%2FGet-The-Picture/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29299541,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-10T12:55:56.056Z","status":"ssl_error","status_checked_at":"2026-02-10T12:55:55.692Z","response_time":65,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cobol","cobol-conversion","cobol-copybook","cobol-pic","csharp","csharp-library","data-exchange","data-export","deserialization","endian","endianness","endianswap","isam","parser","serialization"],"created_at":"2026-01-21T07:04:22.148Z","updated_at":"2026-03-03T20:01:05.921Z","avatar_url":"https://github.com/LsYueh.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Get The Picture\n\n[![CI](https://github.com/LsYueh/Get-The-Picture/actions/workflows/dotnet.yml/badge.svg?branch=main)](https://github.com/LsYueh/Get-The-Picture/actions/workflows/dotnet.yml)\n[![License](https://img.shields.io/github/license/LsYueh/Get-The-Picture)](/LICENSE)\n[![.NET SDK 8.0](https://img.shields.io/badge/.NET-8.0-blue)](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)\n[![GitHub release](https://img.shields.io/github/v/release/LsYueh/Get-The-Picture)](https://github.com/LsYueh/Get-The-Picture/releases)\n\nModern .NET library for working with COBOL Copybook–based data  \n用於處理以 COBOL Copybook 為基礎資料的現代 .NET 類別庫  \n\n\u003e **讀懂你 COBOL 的明白**  \n\n## 開發需求\n- **.NET 8.0** 或更新版本\n- **C# 12** 或相容版本（.NET 8 預設）\n\n## 輸入格式需求\n- COBOL Copybook (`.cpy`) 純文字檔案\n- ASCII / CP950 編碼\n\n\u003cbr\u003e\u003cbr\u003e\n\n# 專案目的\n\u003e 透過簡單的文字 `X` 與數字 `9 / S9`，我們建構出長達百年的金融體系。  \n\n\u003cbr\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eTL;DR\u003c/summary\u003e\n\nCOBOL 的 `PICTURE` 子句，以極少的符號，精確地描述出資料的**型態、長度、符號位、顯示格式與儲存語意**。\n這套設計方式歷經數十年的實務驗證，支撐了銀行、保險、政府與大型企業的核心系統，至今仍在持續運作。\n\n\u003cbr\u003e\n\n然而，在現代語言（例如C#、Java、TypeScript、Rust）中，這些語意往往被**隱含、分散或遺失**：\n\n* `string` 與 `number` 無法完整表達 **定長、補零、符號位置、顯示與儲存差異**\n* 解析邏輯常以 ad-hoc 的 `TryParse`、正則或硬編碼規則存在\n* PIC 與現代型別之間缺乏**可驗證、可測試、可組合**的轉換模型\n\n\u003cbr\u003e\n\n本專案的目的，是將 `COBOL PICTURE` 子句視為一種 **明確的資料規格（Data Specification）**，並：\n\n### 將 PIC 語意轉換為可映射的現代資料模型\n\n* 明確區分 **顯示格式（DISPLAY）** 與 **實際數值語意**\n* 將 `9 / S9 / V / X / A` 等元素拆解為結構化資訊\n* 建立可對應至現代語言型別（`int / long / decimal / string` 等）的判斷依據\n\n### 建立可組合、可擴充的 Decode / Encode 流程\n\n* 以 **Fluent / Builder 風格**描述解析上下文\n* 將「字串 → 型別」與「型別 → 字串」視為對等的一階公民\n* 讓轉換過程可被單元測試、驗證與重構\n\n\u003c/details\u003e\n\n### 降低 COBOL 與現代系統整合的心智與實作成本\n\n* 避免重複撰寫易出錯的解析邏輯\n* 提供一致、可預期的行為邊界（精度、符號）\n* 作為資料轉換、系統汰換、或雙軌運行的一部分\n\n\n### 保留歷史系統的「語意」，而不只是資料\n\n⚠️ 本專案不試圖「現代化」COBOL語言，而是**尊重並保存其資料設計哲學**，使其能被現代語言理解、驗證與安全地使用。\n\n\u003cbr\u003e\n\n## 適用情境\n\n* 核心系統資料轉出\n* COBOL 與現代服務的資料交換層\n* 舊系統重構或漸進式汰換\n* 對 PIC 規格進行靜態分析或測試驗證\n\n\u003cbr\u003e\u003cbr\u003e\n\n\n# COBOL Copybook\n`Copybook` 是 COBOL 中用來定義資料結構的重用檔案，透過 COPY 指令引入，常用於描述檔案格式、資料欄位配置與記憶體布局。在大型主機與金融系統中，Copybook 是資料交換與系統整合的核心。  \n\nCopybook 通常包含：\n- 欄位階層（Level Number）\n- 資料型別與長度（PIC 子句）\n- 儲存格式（如 DISPLAY、COMP、COMP-3）\n\n由於 Copybook 直接對應到位元與位元組配置，它不僅是程式碼的一部分，更是系統間共用的資料規格說明書。  \n\n\u003cbr\u003e\n\n## Copybook Wrapper\n\nCopybook Wrapper 是一個 Raw Buffer 層級的存取工具。提供**欄位級別抽象存取**，不需要傳統的 DTO（`Data Transfer Object`，資料傳輸物件）或序列化/反序列化過程。\n\n![work flow](docs/get-the-picture/wrapper-work-flow.png)  \n\n\u003cdetails\u003e\n    \u003csummary\u003eWrapper vs Serialization（序列化）\u003c/summary\u003e\n\n| 功能         | Wrapper                      | Serialization |\n| ---------- | ------------------------------- | --------------- |\n| Raw ↔ 物件   | 不需要 DTO，直接欄位級存取                 | Yes, 一次性 DTO    |\n| 欄位抽象化      | Yes，靠 `CbAddress` + indexer/屬性 | No / 需要 mapping |\n| Memory 複製  | 幾乎零複製，Span 直接操作 Raw             | 全部複製            |\n| 動態欄位讀寫     | 內建 indexer 或強型別屬性               | 一般不方便           |\n| 物件圖 / 狀態管理 | No，Raw 是唯一來源                    | Yes             |\n\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n### 使用方式\n資料物件需**繼承**核心物件 `CbWrapper`，根據 Copybook 定義，透過 `CbAddress` 設定每個欄位的起始位置、長度及格式。  \n- 可透過 indexer 或 **強型別屬性**存取欄位\n- 支援即時驗證 Raw Buffer 長度是否符合欄位配置\n\n\u003cbr\u003e\n\n程式碼範例：櫃買中心 T30 漲跌幅度資料  \n\n```csharp\nconst string s = \"11011 00106600000096950000087300020251219000000  0台泥一永        000000000000000000000 0           \";\n\nbyte[] raw = cp950.GetBytes(s);\n        \nvar T30 = new T30_t(raw);\n\nConsole.WriteLine(T30.StockNo);   // \"11011\"\nConsole.WriteLine(T30.StockName); // \"台泥一永\"\nConsole.WriteLine(T30.LastMthDate); // \"2025-12-19\"\n```\n\n\u003cbr\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eT30_t\u003c/summary\u003e\n\n```csharp\npublic class T30_t(byte[] raw) : CbWrapper(raw)\n{\n    // ----------------------------\n    // Copybook Address Map\n    // ----------------------------\n\n    protected override Dictionary\u003cstring, CbAddress\u003e AddressMap { get; } = new Dictionary\u003cstring, CbAddress\u003e\n    {\n        [\"STOCK-NO\"]      = new CbAddress( 1, 6, \"X(6)\"),\n        [\"BULL-PRICE\"]    = new CbAddress( 7, 9, \"9(5)V9(4)\"),\n        [\"LDC-PRICE\"]     = new CbAddress(16, 9, \"9(5)V9(4)\"),\n        [\"BEAR-PRICE\"]    = new CbAddress(25, 9, \"9(5)V9(4)\"),\n        [\"LAST-MTH-DATE\"] = new CbAddress(34, 8, \"9(8)\", PicSemantic.GregorianDate), // 用語意方式轉換\n        [\"SETTYPE\"]       = new CbAddress(42, 1, \"X(01)\"),\n        [\"MARK-W\"]        = new CbAddress(43, 1, \"X(01)\"),\n        [\"MARK-P\"]        = new CbAddress(44, 1, \"X(01)\"),\n        [\"MARK-L\"]        = new CbAddress(45, 1, \"X(01)\"),\n        [\"IND-CODE\"]      = new CbAddress(46, 2, \"X(02)\"),\n        [\"IND-SUB-CODE\"]  = new CbAddress(48, 2, \"X(02)\"),\n        [\"MARK-M\"]        = new CbAddress(50, 1, \"X(01)\"),\n        [\"STOCK-NAME\"]    = new CbAddress(51,16, \"X(16)\"),\n        // MARK-W\n            [\"MATCH-INTERVAL\"] = new CbAddress(67, 3, \"9(03)\"),\n            [\"ORDER-LIMIT\"]    = new CbAddress(70, 6, \"9(06)\"),\n            [\"ORDERS-LIMIT\"]   = new CbAddress(76, 6, \"9(06)\"),\n            [\"PREPAY-RATE\"]    = new CbAddress(82, 3, \"9(03)\"),\n        [\"MARK-S\"]        = new CbAddress(85, 1, \"X(01)\"),\n        [\"STK-MARK\"]      = new CbAddress(86, 1, \"X(01)\"),\n        [\"MARK-F\"]        = new CbAddress(87, 1, \"X(01)\"),\n        [\"MARK-DAY-TRADE\"]= new CbAddress(88, 1, \"X(01)\"),\n        [\"STK-CTGCD\"]     = new CbAddress(89, 1, \"X(01)\"),\n        [\"FILLER\"]        = new CbAddress(90,11, \"X(11)\"),\n    };\n\n    // ----------------------------\n    // 強型別屬性\n    // ----------------------------\n\n    public string StockNo\n    {\n        get =\u003e this[\"STOCK-NO\"].Get\u003cstring\u003e();\n        set =\u003e this[\"STOCK-NO\"].Set(value);\n    }\n\n    public decimal BullPrice\n    {\n        get =\u003e this[\"BULL-PRICE\"].Get\u003cdecimal\u003e();\n        set =\u003e this[\"BULL-PRICE\"].Set(value);\n    }\n\n    public decimal LdcPrice\n    {\n        get =\u003e this[\"LDC-PRICE\"].Get\u003cdecimal\u003e();\n        set =\u003e this[\"LDC-PRICE\"].Set(value);\n    }\n\n    public decimal BearPrice\n    {\n        get =\u003e this[\"BEAR-PRICE\"].Get\u003cdecimal\u003e();\n        set =\u003e this[\"BEAR-PRICE\"].Set(value);\n    }\n\n    public DateOnly LastMthDate\n    {\n        get =\u003e this[\"LAST-MTH-DATE\"].Get\u003cDateOnly\u003e();\n        set =\u003e this[\"LAST-MTH-DATE\"].Set(value);\n    }\n\n    // (略...)\n}\n```\n\n\u003c/details\u003e\n\n\u003cbr\u003e\n\n📖 更多關於 [Copybook Compiler](docs/get-the-picture/copybook/compiler.md) ...  \n📖 更多關於 [Copybook Resolver](docs/get-the-picture/copybook/resolver.md) ...  \n📖 更多關於 Sub-Class Generator : [Forge](docs/forge/forge.md) ...  \n\n\u003cbr\u003e\u003cbr\u003e\n\n\n# COBOL Coding Sheet (Reference Format)\n\n![punched card](/docs/source/punched-card.webp) \n\nCOBOL 程式有一套固定的欄位規則，尤其在 `固定格式（Fixed Format）` 下很重要。主要分為 `Sequence Area`, `Indicator Area`, `Area A`, `Area B` 等區域。  \n\n\u003cbr\u003e\n\n```cobol\n|...+.*..1....+....2....+....3....+....4....+....5....+....6....+....7..\n       01 ORDER-RECORD.\n           05 ORDER-ID           PIC 9(6).\n           05 ORDER-DATE         PIC 9(8).\n           05 ORDER-AMOUNT       PIC S9(7)V99 COMP-3.\n```\n\n\u003cbr\u003e\n\n| 位置 (Column) | 說明                                                                 |\n| ----------- | ------------------------------------------------------------------ |\n| 1–6         | **Sequence Number**（序號欄，可選）：用於列印或版本控制。                             |\n| 7           | **Indicator Area**（指示欄）：\u003cbr\u003e - `*`：註解\u003cbr\u003e - `/`：換頁\u003cbr\u003e - `-`：延續上一行 |\n| 8–11        | **Area A**：段落名稱、Section 名稱、DIVISION 關鍵字等。                          |\n| 12–72       | **Area B**：語句、指令、變數宣告、程式碼本體。                                       |\n| 73–80       | **Identification Area**（識別欄，可選）：通常用於序號或其他控制用途。                     |\n\n\u003e 現代 COBOL `(Free Format) ` 已經不限制欄位，但固定格式仍常用於舊系統。  \n\n\u003cbr\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eℹ️ \"Elementary Data Item\" and \"Group Item\"\u003c/summary\u003e\n\n| 面向                    | Elementary Data Item    | Group Item             |\n| --------------------- | ----------------------- | ---------------------- |\n| 定義角色                  | **最小資料單位（leaf）**        | **結構性容器（composite）**   |\n| 是否可包含子項目              | ❌ 不可                    | ✅ 可                    |\n| 是否有 `PIC` 子句          | ✅ **必須有**               | ❌ **不可有**              |\n| 是否直接描述資料型態            | ✅ 是（數值、字元、COMP、COMP-3…） | ❌ 否（由子項目間接決定）          |\n| 是否可直接被 MOVE / COMPUTE | ✅ 可                     | ⚠️ 可（視情況，為整段記憶體移動）     |\n| 記憶體佔用                 | 由 `PIC` 決定              | 為所有子項目記憶體的總和           |\n| 可否有 `OCCURS`          | ✅ 可                     | ✅ 可                    |\n| 可否有 `REDEFINES`       | ✅ 可                     | ✅ 可                    |\n| 可否有 `VALUE`           | ✅ 可                     | ❌（標準上 group 不定義 VALUE） |\n| 是否為樹的葉節點              | ✅ 是                     | ❌ 否                    |\n| COBOL 規格名稱            | *Elementary data item*  | *Group item*           |\n\n\u003cbr\u003e\n\n📖 更多關於 [Elementary Data Item](docs/get-the-picture/cobol/ElementaryDataItem.md) ...  \n\n\u003c/details\u003e\n\n\u003cbr\u003e\u003cbr\u003e\n\n\n# COBOL DATA DIVISION (Data description entry)\n\n用於描述程式中所有資料的結構、型態與儲存方式。\n\n**Format 1**  \n```\n\u003clevel-number\u003e \u003cdata-name-1\u003e\n    [REDEFINES \u003cdata-name-2\u003e]\n    [PICTURE \u003ccharacter-string\u003e]\n    [USAGE \u003cusage-type\u003e]\n    [OCCURS \u003cn\u003e TIMES]\n    [VALUE \u003cliteral-1\u003e].\n```\n\n\u003cbr\u003e\n\n**Format 2**  \n```\n66 \u003cdata-name-1\u003e RENAMES \u003cdata-name-2\u003e THRU \u003cdata-name-3\u003e.\n```\n\n\u003cbr\u003e\n\n**Format 3**  \n```\n88 \u003ccondition-name-1\u003e VALUE \u003cliteral-1\u003e [THRU \u003cliteral-2\u003e].\n```\n\n\u003cbr\u003e\n\n## 📋 Format 支援狀態\n\n| Format   | 語法用途                            | 支援狀態  | 說明                                            |\n| -------- | ------------------------------- | ----- | --------------------------------------------- |\n| Format 1 | 一般資料項目（Group / Elementary Item） | ✅ 支援  | 用於描述資料結構、型別、PIC、USAGE、OCCURS 等，是目前解析與生成的核心格式。 |\n| Format 2 | `66 RENAMES`                    | ⚠️ 有限支援 | 屬於語意別名（Alias）的定義，不影響實際的資料儲存結構；相關別名可由 Wrapper 於應用層自行進行二次定義。 |\n| Format 3 | `88 LEVEL` 條件名稱                 | ❌ 未支援 | 為條件常數定義（Condition Name），本身不佔用任何實體儲存空間。 \u003cbr/\u003e 當與 OCCURS 子句混合使用時，條件判斷的呼叫與對應關係在實作上較為複雜，易影響可讀性與使用一致性，建議直接呼叫 Wrapper 內的屬性來處理。 |\n\n\u003cbr\u003e\u003cbr\u003e\n\n\n# Level Numbers\n\nCOBOL 使用 `Level Number`（層級號） 來描述資料結構，主要有：\n\n| Level       | 用途             | 說明                  |\n| ----------- | -------------- | ------------------- |\n| **01**      | 主結構            | 定義檔案或記錄的頂層結構        |\n| **02 … 49** | 子結構            | 01 之下的子群組或欄位，形成巢狀結構 |\n| **66**      | RENAMES        | 將已有欄位重新命名或形成別名區段    |\n| **77**      | 單一變數           | 不屬於群組，獨立使用          |\n| **88**      | Condition Name | 定義邏輯條件（True/False）  |\n\n\u003e ⚠️ Level number 越小層級越高，01 是最外層。\n\n\u003cdetails\u003e\n    \u003csummary\u003e📖 更多關於特殊層級 ... \u003c/summary\u003e\n\nLevel 66 — [RENAMES](docs/get-the-picture/cobol-level-numbers/lv66.md)  \nLevel 77 — [Standalone Variable (單一變數)](docs/get-the-picture/cobol-level-numbers/lv77.md)  \nLevel 88 — [Condition Name](docs/get-the-picture/cobol-level-numbers/lv88.md)  \n\n\u003c/details\u003e\n\n\u003cbr\u003e\u003cbr\u003e\n\n\n# REDEFINES 子句\n\n## 與 `66 RENAMES` 的差異\n|            | RENAMES         | REDEFINES       |\n| ---------- | --------------- | --------------- |\n| 影響 storage | ❌               | ✅               |\n| 改變 offset  | ❌               | ✅（對齊另一個）        |\n| 本體是        | 邏輯群組            | **GroupItem**   |\n| 最終表現       | View / Property | View / Property |\n\n\u003cbr\u003e\n\n## 支援說明\n\n在 IBM 提供的 [REDEFINES clause](https://www.ibm.com/docs/en/cobol-linux-x86/1.2.0?topic=entry-redefines-clause) 文件中，整理出幾種 `REDEFINES` 可能的使用與法規則：\n\n\u003cdetails\u003e\n    \u003csummary\u003eCASE 1：Group REDEFINES Elementary Data Item\u003c/summary\u003e\n\n    ```cobol\n    05  A PICTURE X(6).\n    05  B REDEFINES A.\n        10 B-1          PICTURE X(2).\n        10 B-2          PICTURE 9(4).\n    05  C               PICTURE 99V99.\n\n    ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eCASE 2：01-level + GLOBAL\u003c/summary\u003e\n\n    ```cobol\n    01 A1 PICTURE X(6). \n    01 B1 REDEFINES A1 GLOBAL PICTURE X(4). \n    ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eCASE 3：多個 REDEFINES 指向同一 target\u003c/summary\u003e\n\n    ```cobol\n    05  A               PICTURE 9999.\n    05  B REDEFINES A   PICTURE 9V999.\n    05  C REDEFINES A   PICTURE 99V99.\n    ```\n\u003c/details\u003e\n\n\u003cdetails\u003e\n    \u003csummary\u003eCASE 4：REDEFINES 鏈\u003c/summary\u003e\n\n    ```cobol\n    05  A               PICTURE 9999.\n    05  B REDEFINES A   PICTURE 9V999.\n    05  C REDEFINES B   PICTURE 99V99.\n    ```\n\u003c/details\u003e\n\n### 📋 支援狀態總覽\n\n| Case | 用法說明 | 支援狀態 | 說明 |\n|------|----------|----------|------|\n| CASE 1 | Group REDEFINES Elementary Data Item | ✅ 支援 | 最常見且結構單純的用法。Group 僅作為 Elementary Item 的另一種結構化視角，不引入額外 storage。 |\n| CASE 2 | 01-level REDEFINES + GLOBAL | ❌ 不支援 | 涉及 01-level overlay 與 GLOBAL 可視範圍，在高階語言中難以安全對應。 |\n| CASE 3 | 多個 REDEFINES 指向同一 target | ⚠️ 有限支援 | 會形成多重 storage alias，容易造成資料覆寫與語意不明確。 |\n| CASE 4 | REDEFINES 鏈（REDEFINES 已 REDEFINES 的 item） | ⚠️ 有限支援 | 需解析並正規化多層 alias 關係，實作與維護成本過高。 |\n\n\u003cbr\u003e\n\n再根據這篇 [Redefined data items and OCCURS clauses](https://www.ibm.com/docs/en/cobol-linux-x86/1.2.0?topic=changes-redefined-data-items-occurs-clauses) 的說明，裡面提到：\n\n\u003e According to Standard `COBOL 2002`, the data item being redefined cannot contain an OCCURS clause.  \n\n所以本專案亦不支援過於複雜的 REDEFINES 運作行為。\n\n\u003cbr\u003e\u003cbr\u003e\n\n\n# PICTURE 子句\n\n![PICTURE clause](docs/get-the-picture/cobol-picture/picture-clause.png)  \n\n支援的 ***character-string*** (`Symbols`) 語法  \n\n| Alphabetic | Alphanumeric | Numeric | Numeric (With Sign) |\n| :--------: | :----------: | :-----: | :-----------------: |\n| A.. \u003cbr\u003e A(n) | X.. \u003cbr\u003e X(n) | 9... \u003cbr\u003e 9(n) \u003cbr\u003e 9...V9... \u003cbr\u003e 9(n)V9(m) \u003cbr\u003e 9(n)V9... | S9... \u003cbr\u003e S9(n) \u003cbr\u003e S9...V9... \u003cbr\u003e S9(n)V9(m) \u003cbr\u003e S9(n)V9... |\n\n\u003cbr\u003e\n\n## 類別(`Category`)資料\n\n- [文字 (`Alphabetic`/`Alphanumeric`)](docs/get-the-picture/cobol-picture/category/alphabetic-alphanumeric.md)  \n- [數字 (`Numeric`)](docs/get-the-picture/cobol-picture/category/numeric.md)  \n    - [`S9`數字轉換規則](docs/get-the-picture/other-topics/pic-s9-overpunch.md)  \n\n\u003cbr\u003e\n\n## 語意(`Semantic`)資料\n\n- [日期 (`Date`)](docs/get-the-picture/cobol-picture/semantic/date-time/date.md)  \n- [時間 (`Time`)](docs/get-the-picture/cobol-picture/semantic/date-time/time.md)  \n- [時間戳記 (`Timestamp`)](docs/get-the-picture/cobol-picture/semantic/date-time/timestamp.md)  \n- [布林值 (`Boolean`)](/docs/get-the-picture/cobol-picture/semantic/boolean.md)\n\n\u003cbr\u003e\n\n📖 更多關於 [PICTURE Clause Codec](docs/get-the-picture/cobol-picture/codec.md) ...  \n\n\u003cbr\u003e\u003cbr\u003e\n\n\n# USAGE 子句\n\n![USAGE clause](docs/get-the-picture/usage-clause.png)  \n\n`USAGE` 定義欄位在記憶體中的儲存方式，影響資料的物理編碼與運算行為。  \n- DISPLAY（預設）：以可讀**字元**存放，每個數字或字母對應一個 byte，便於輸入輸出與檢視。  \n- ***COMPUTATIONAL***：用**電腦原生格式**儲存，只用於 `Numeric` 欄位。\n    - COMP-3（Packed Decimal）：將兩個數字壓縮在一個 nibble，最後一個 nibble 用於符號，節省空間且方便算術運算。  \n    - COMP-4（Binary）/ COMP-5（Native Binary）：以二進位形式存放，運算效率高 (對 COBOL 而言)，但不可直接讀取文字。  \n    - COMP-6（Unsigned Packed Decimal）：非標準 COBOL 定義。與 COMP-3 方式一樣，但是沒有 sign nibble。\n\n\u003cbr\u003e\n\nUSAGE 項目的適用範圍:  \n| Class | Category/Semantic | Usage |\n| :---: | :---------------: | ----- |\n| Alphabetic | Alphabetic | DISPLAY |\n| Alphanumeric | Alphanumeric | DISPLAY |\n| Numeric | Numeric | DISPLAY \u003cbr\u003e COMP (Binary) \u003cbr\u003e COMP-3 (Packed Decimal) \u003cbr\u003e COMP-4 (Binary) \u003cbr\u003e COMP-5 (Native Binary) \u003cbr\u003e COMP-6 (Unsigned Packed Decimal) |\n| Date-Time | Date \u003cbr\u003e Time \u003cbr\u003e Timestamp | DISPLAY |\n\n\u003cbr\u003e\n\n📖 更多關於 [COMPUTATIONAL 轉換規則](/docs/get-the-picture/other-topics/cobol-computational.md) ...  \n\n\u003cbr\u003e\u003cbr\u003e\n\n\n# Performance\n\n## 數據內容\n- 根據**櫃買中心** (OTC) 規格改寫的 `T30.CPY` (包含註解)：DataItem 24 個   \n- 部分**櫃買中心** (OTC) 的 `T30.DAT`：漲跌幅度資料 55 筆   \n\n\u003cbr\u003e\n\n執行指令:\n\n\u003e dotnet run -c Release --project GetThePicture.Benchmarks\\GetThePicture.Benchmarks.csproj --filter *   \n\n\u003e dotnet run -c Release --project GetThePicture.Benchmarks\\GetThePicture.Benchmarks.csproj --anyCategories {BenchmarkCategory}  \n\n\u003cbr\u003e\n\n## 跑分結果\n```bash\nBenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.7840/25H2/2025Update/HudsonValley2)\nIntel Core i5-10400 CPU 2.90GHz, 1 CPU, 12 logical and 6 physical cores\n.NET SDK 8.0.418\n  [Host]     : .NET 8.0.24 (8.0.24, 8.0.2426.7010), X64 RyuJIT x86-64-v3\n  DefaultJob : .NET 8.0.24 (8.0.24, 8.0.2426.7010), X64 RyuJIT x86-64-v3\n```\n\n\u003e 1 µs = 1000 ns  \n\n\u003cbr\u003e\n\n### Wrapper\n\n| Method                | Mean     | Error     | StdDev    |\n|---------------------- |---------:|----------:|----------:|\n| Wrapper_Read_String   | 4.362 μs | 0.0176 μs | 0.0156 μs |\n| Wrapper_Write_String  | 4.267 μs | 0.0222 μs | 0.0186 μs |\n| Wrapper_Read_Integer  | 4.511 μs | 0.0249 μs | 0.0233 μs |\n| Wrapper_Write_Integer | 5.450 μs | 0.0198 μs | 0.0165 μs |\n| Wrapper_Read_Decimal  | 5.895 μs | 0.0376 μs | 0.0333 μs |\n| Wrapper_Write_Decimal | 9.589 μs | 0.0614 μs | 0.0574 μs |\n\n\u003e ⚠️ T30 的資料內沒有進行 `COMP`，目前的 Wrapper 跑分算是 Best Case。  \n\u003e ⚠️ Wrapper 只做**單筆欄位**讀取。  \n\n\u003cbr\u003e\n\n### DISPLAY\n\nInteger: `PIC 9(18)` / `PIC S9(18)`   \nDecimal: `PIC S9(5)V9(2)`  \n\n| Method                       | Mean      | Error    | StdDev   |\n|----------------------------- |----------:|---------:|---------:|\n| Display_Read_Integer         |  79.69 ns | 0.447 ns | 0.418 ns |\n| Display_Write_Integer        | 113.33 ns | 0.418 ns | 0.370 ns |\n| Display_Read_Signed_Integer  |  98.95 ns | 0.496 ns | 0.464 ns |\n| Display_Write_Signed_Integer | 183.39 ns | 0.948 ns | 0.840 ns |\n| Display_Read_Decimal         |  97.51 ns | 0.309 ns | 0.274 ns |\n| Display_Write_Decimal        | 206.42 ns | 0.992 ns | 0.928 ns |\n\n\u003cbr\u003e\n\n### COMP-3\n\nInteger: `PIC 9(18)` / `PIC S9(18)`   \nDecimal: `PIC S9(5)V9(2)`  \n\n| Method                     | Mean      | Error    | StdDev   |\n|--------------------------- |----------:|---------:|---------:|\n| Comp3_Read_Integer         |  87.85 ns | 0.218 ns | 0.182 ns |\n| Comp3_Write_Integer        |  88.29 ns | 0.446 ns | 0.372 ns |\n| Comp3_Read_Signed_Integer  |  84.39 ns | 0.440 ns | 0.412 ns |\n| Comp3_Write_Signed_Integer |  91.66 ns | 0.343 ns | 0.304 ns |\n| Comp3_Read_Decimal         |  96.58 ns | 0.642 ns | 0.601 ns |\n| Comp3_Write_Decimal        | 151.53 ns | 1.131 ns | 1.058 ns |\n\n\u003cbr\u003e\n\n### COMP-4 (BE)\n\nInteger: `PIC 9(18)` / `PIC S9(18)`  \n\n| Method                     | Mean      | Error    | StdDev   |\n|--------------------------- |----------:|---------:|---------:|\n| Comp4_Read_Integer         |  41.56 ns | 0.201 ns | 0.178 ns |\n| Comp4_Write_Integer        | 129.20 ns | 0.395 ns | 0.330 ns |\n| Comp4_Read_Signed_Integer  |  42.06 ns | 0.154 ns | 0.129 ns |\n| Comp4_Write_Signed_Integer | 132.84 ns | 0.555 ns | 0.463 ns |\n\n\u003cbr\u003e\n\n### COMP-5\n\nInteger: `PIC S9(18)`  \n\n| Method                 | Mean      | Error    | StdDev   |\n|----------------------- |----------:|---------:|---------:|\n| Comp5_Read_Integer_BE  |  40.91 ns | 0.223 ns | 0.209 ns |\n| Comp5_Write_Integer_BE | 132.44 ns | 0.655 ns | 0.580 ns |\n| Comp5_Read_Integer_LE  |  40.76 ns | 0.253 ns | 0.224 ns |\n| Comp5_Write_Integer_LE | 132.85 ns | 0.747 ns | 0.663 ns |\n\n\u003cbr\u003e\n\n### COMP-6\n\nInteger: `PIC 9(18)`  \n\n| Method              | Mean     | Error    | StdDev   |\n|-------------------- |---------:|---------:|---------:|\n| Comp6_Read_Integer  | 84.26 ns | 0.365 ns | 0.323 ns |\n| Comp6_Write_Integer | 92.26 ns | 0.246 ns | 0.192 ns |\n\n\u003cbr\u003e\u003cbr\u003e\n\n\n# 參考\n\nRocket Software ACUCOBOL-GT extend (V10.5.0) : [USAGE Clause](https://docs.rocketsoftware.com/bundle/acucobolgt_dg_1050_html/page/BKRFRFDATAS043.html)  \nIBM Enterprise COBOL for z/OS (6.5.0) : [USAGE clause](https://www.ibm.com/docs/en/cobol-zos/6.5.0?topic=entry-usage-clause)  \nIBM Enterprise COBOL for z/OS (6.5.0) : [RECORD KEY clause](https://www.ibm.com/docs/en/cobol-zos/6.5.0?topic=section-record-key-clause)  \nIBM COBOL for Linux on x86 (1.2.0) : [Classes and categories of data](https://www.ibm.com/docs/en/cobol-linux-x86/1.2.0?topic=relationships-classes-categories-data)  \n\n\u003cbr\u003e\u003cbr\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flsyueh%2Fget-the-picture","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flsyueh%2Fget-the-picture","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flsyueh%2Fget-the-picture/lists"}