> For the complete documentation index, see [llms.txt](https://overleaf-pro.ayaka.space/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://overleaf-pro.ayaka.space/latex/zh-tw/shen-ru-wen-zhang/05-an-introduction-to-endlinechar-how-tex-reads-lines-from-text-files.md).

# \endlinechar 簡介：TeX 如何從文字檔讀取行

作為人類，我們偏好以逐行方式檢視與編輯文字檔。當我們覺得某一行文字已經夠長時，就會在（文字編輯器中）按下「return」以表示該行結束。在幕後，你的文字編輯器會把這解讀為一個指示，要求在 [換行字元](https://en.wikipedia.org/wiki/Newline) 你決定斷行的位置。

然而，事情若真有那麼簡單就好了：問題在於，不同作業系統對何謂換行字元有不同的定義。更糟的是，Windows 會依據檔案是否以所謂的 [*二進位模式* 或 *文字模式*](https://docs.microsoft.com/en-us/cpp/c-runtime-library/text-and-binary-mode-file-i-o?view=vs-2017)開啟而以不同方式處理換行字元。結果是，視主機作業系統而定，文字檔中的各行可能會以不同組合的字元作結，這些字元稱為 *回車* （ASCII／Unicode 字元 13）以及 *換行* （ASCII／Unicode 字元 10）：記為 `\r` 以及 `\n` ，分別如此。

顯然，若要做到與系統無關，TeX 需要一種方法來處理它在讀取與處理的文字檔中，用來終止一行的不同字元所引入的各種變異。

### TeX 的輸入緩衝區

你也許會，也也許不會，對此感到驚訝：TeX 引擎（包括 LuaTeX 和 XeTeX）是逐行讀取輸入檔案的：它們不會把整個文字檔讀入記憶體。儘管 TeX 引擎處理的大多數文字檔，相較於現代裝置上可用的記憶體而言都微不足道，但檔案中的每一行都會各自被讀入並儲存在一個小型的內部緩衝區中。不過，當然，TeX 讀取並儲存一行的過程還有一些額外的變化。

## 「我走我的路」——TeX 的 \endlinechar 指令

當 TeX 從輸入檔案讀入另一行文字時，它會執行兩個「整理工作」：

* 它會移除在行尾找到的任何終止換行字元（\r 或 \n）——也就是說，它會剔除文字檔原本儲存到磁碟時所加入的所有行尾符號；
* 它也會移除在行尾找到的所有尾端空白字元。

這兩個處理會在 TeX 真正開始掃描該行本身所包含的字元之前發生：可以把它們看作是為下一個處理階段（掃描）做準備的一種「整理工作」。因此，在這個讀行過程的初始階段，TeX 已經剝除了所有與平台相關的行尾符號（以及任何尾端空白）：那麼 TeX 要怎麼知道（偵測）那一行是在什麼地方結束的呢？TeX 還有另一個「絕招」： `\endlinechar` 來完成的。

為了避免平台相依的換行字元問題，TeX 引入了 `\endlinechar`，這是一個可由使用者定義的參數，TeX 會利用它在剛從檔案讀入的一行文字最末端插入自己專用的行尾字元。再次注意，這是在 TeX 實際開始掃描字元之前發生的——這是 TeX 在準備開始讀取（掃描）該行所含的實際字元前，最後一道「整理工作」。

TeX 會使用儲存在 `\endlinechar` 中的值來加入它自己的行尾終止字元，若且唯若， `\endlinechar` 被適當地定義——在 Knuth 的 TeX 中，這表示它必須具有大於 -1 且小於 256 的值。通常， `\endlinechar` 會被指定為 13：也就是回車字元——通常記為 `\r` ，在程式設計文獻中。

但如果你寫下 `\endlinechar=-1` 在你的輸入內容中的某處，那麼 *下次* TeX 從檔案讀取一行文字時，它將不會 *不是* 在行尾加入任何額外的終止字元。因此，你的輸入會被視為一整段連續的文字字串，直到你把 `\endlinechar` 重設為適當的值——通常是 13（`\r`):

```latex
\endlinechar=13
```

TeX 的 16 種類別代碼之一（值 5）被保留來識別「行尾」字元，而這通常就是那個會 `\endlinechar` 插入——而且只有在 `\endlinechar` 的值設為適當值時才會被插入。

## 行尾處理摘要

雖然這些細節相當底層，但對任何想探索撰寫處理文字行讀取的巨集的人來說，都會很有興趣。

1. 當 TeX 從你的檔案讀取一行時，它會先剔除所有行尾字元（`\r` 以及 `\n`）——也就是文字編輯器在儲存檔案時加入的。除此之外：

* TeX 也會剔除行尾的任何尾端空白字元；
* TeX *不會* 移除尾端的定位字元（ASCII 字元代碼 9）。

**補充**：LuaTeX 的其中一個原始碼檔案，也就是包含執行這項空白剔除程式碼的那個檔案，含有以下註記：

> （引自檔案 `luatex.c`）「David Fuchs 提到，之所以進行這項［空白］剔除，是為了確保 TeX 文件的可攜性，因為當時某些系統（例如 IBM VM/CMS 與 OS/360）在固定記錄的『行』上會以空白做填補。」

3. 在步驟 (1) 之後，TeX 會加入（插入）一個額外字元，其值儲存在 \endlinechar 中（前提是它有被適當定義：大於 -1 且小於 256）
4. \endlinechar 通常設定為 13（`\r`），這表示在步驟 (2) 中加入的字元通常是字元 13（`\r`）——但當然，你也可以將 \endlinechar 設為其他值，透過巨集程式設計達成特殊效果。
5. 當其輸入掃描例程偵測到字元 `\r` （字元代碼 13）位於其內部緩衝區尾端時，TeX 會照例檢查其類別代碼，以決定如何處理它。
6. 字元 13 *通常* 的類別代碼值為 5（「行尾」），除非它的類別代碼已被更改——有些巨集會讓行尾字元成為啟用字元，以便進行更複雜的處理。
7. 視 TeX 的內部狀態（實際上也就是它正在做什麼）而定，TeX 可以把行尾字元（通常是 `\r`，類別代碼 5）轉換成空白字元——這就是行尾字元變成空白的方式。
8. 另外要注意，TeX 會使用類別代碼 5 的字元來偵測何時已讀到空白行，並需要產生一個 `\par` 記號。

下圖以視覺方式總結步驟 (1) 與 (2)：剔除換行字元與尾端空白字元，以及插入 `\endlinechar` 以準備好進行輸入掃描的工作。

![TeX 如何使用 \endlinechar](/files/3ddbb526fab2bb220a6ff9d7b79fac8fdcf0f88e)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://overleaf-pro.ayaka.space/latex/zh-tw/shen-ru-wen-zhang/05-an-introduction-to-endlinechar-how-tex-reads-lines-from-text-files.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
