4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

完全解説! Typstでのバックスラッシュの使い方

Last updated at Posted at 2025-12-20

巷ではよくTypstは「バックスラッシュをあまり書かない組版ソフトウェア」と認識されているようです。しかしもちろん、Typstでも(特に数式モードで)バックスラッシュ(文字「\」=U+005C)が必要になる場合が結構あります。本記事ではTypstの文書ソースにおけるバックスラッシュ文字の用法について解説します。

本記事の例示文書では本文フォントとして「原ノ味明朝」を指定しています。

前提知識

  • Typstの3つのモード(マークアップ・数式・コード)についての理解。

マークアップモード/数式モードの場合

マークアップモードおよび数式モードにおいては、バックスラッシュ文字は以下の3つの用法をもちます。

  • \‹空白文字›1改行linebreakエレメント)を表します。
  • \u{Unicodeエスケープを開始します。
  • 上記以外の\‹文字›は特殊文字でない通常の‹文字›自体を表します(リテラル化)。例えば\@は「refの短縮表記」ではない@そのものを表します。

以下でそれぞれの用法について説明します。

改行の短縮表記

\の直後の文字がUnicode空白文字(典型的にはASCII空白(U+0020)や改行文字(U+000A))である場合は、その\改行の短縮表記と見なされてlinebreakエレメントに置き換えられます。

(マークアップモード)
Typst is great.\ Sushi is delicious.

$ // 数式モードでの用法
  x + y &= 96 \
  x - y &= 12
$

image-01.png

なお細かい話になりますが、\の後にある空白文字自体はそのまま残ると考えられます。

(マークアップモード)
#repr[A\ B]

image-02a.png

しかしTypstの組版規則として改行の直後にあるASCII空白は抑止されます。またタブ(U+0009)や改行は入力規則上でASCII空白に正規化されるため、「\の後がASCII空白・タブ・改行」という典型的なケースでは空白は結局出力されません。これに対して\の後がその他のUnicode空白文字の場合は空白が実際に出力されます。

(マークアップモード)
// "\"の直後に全角空白(U+3000)がある
Typstは\ アレ。

image-03.png

また本当に細かい話ですが、マークアップコードの末尾に\がある場合もそれは改行と見なされます。次のような(やや技巧的な)コードで確かめられます2

(マークアップモード)
// linbreakで改行せずに代わりに"BREAK"と書く
#show linebreak: "BREAK"

// "B\"でファイルが終了している(改行無し)
A\ B\

image-04.png

Unicodeエスケープ

\u{‹符号値16進›}はその符号値をもつUnicode文字そのもの(リテラル)を表します(Unicodeエスケープ)。

(マークアップモード)
// "\u{2603}"はU+2603の文字"☃"を表す
Here is a \u{2603}.

If $s in { \u{2603} }$, then $s$ is nice.

image-05.png

Unicodeエスケープの開始は\u{で判断されます。直後が{でない\uはUnicodeエスケープにならず、単にuのリテラル化と見なされます。

(マークアップモード)
// これはUnicodeエスケープにならない
Here is a \u {2603}.

image-06.png

\u{でUnicodeエスケープを開始したのに正しい書式で終結していない場合(例えば\u{}\u{42X}\u{42等)はエラーになります。

(マークアップモード)
// ざんねん🙃
Here is a \u{2603ZR}.
//==> ❌エラー: invalid Unicode codepoint: 2603ZR

リテラル化

先述の2つの場合以外の\u‹文字›は単に‹文字›そのものを表します。ここで‹文字›が当該のモードにおいて特殊な意味を持つ文字であったとしても\‹文字›は常に特殊でない通常の(リテラル化された)文字を表します。元々特殊でない文字に\を付けても何も意味はないので、普通は特殊文字に\が付けられます。

マークアップモードでのリテラル化の例です。

(マークアップモード)
// これは参照(ref)ではない
Posted from \@zr_tex8r.

// これはコードモード呼出ではない
Post with hashtag \#Typst.

// これは節見出し(heading)ではない
\= ←equal sign

image-07.png

数式モードでのリテラル化の例です。

(マークアップモード)
// "epsilon\/2"はfracの短縮表記ではない
Then we have $0 <= delta <= epsilon\/2$.

$ // この括弧はlrの短縮表記ではない
  x^3 + y^3 &= \(x + y\)\(x^2 - x y + y^2\) \
  // 比較用: 単純に括弧を書くとlrの短縮表記となり括弧が
  // 自動伸長してしまい, この場合はあまり好ましくない😐
  x^3 - y^3 &= (x - y)(x^2 + x y + y^2) 
$

// 前のコンマは引数区切りではない
$ frac(A\, B, C) $

image-08.png

余談: なぜ自動伸長しない括弧が\(~\)なのか

前節の数式モードでの例で「/\/」および「(~)\(~\)」について動作の違いを示しました。

  • /は分子と分母を縦に並べた分数(fracエレメントの短縮記法)。
  • \/は「/」の文字自体。分数を「a/b」のように書くときに使う。
  • (~)は自動伸長する丸括弧(lrエレメントの短縮記法)。
  • \(~\)は自動伸長しない丸括弧。

これらの組については、文書作成者が自分で判断して適切に使い分ける必要があります。(例で示したように、むやみに(~)を使うと不必要に括弧が伸長する3場合がかなり多いのです。)

これを見ると、単純な「/」「(」「)」を表すのが/()になっていないわけで、これは不自然だと思った人もいるでしょう。特に括弧については(~)よりむしろ\(~\)の方が使用頻度は高い4はずなので、単純な方に\を付けているのは不合理にも思えます。

しかし、前節に述べた「Typstでのバックスラッシュの使い方」の原則を理解すれば、この規則になっている理由が解るはずです。Typstでは一部のASCII記号に特別な機能を割り当てた上で、その記号そのものを表すために「リテラル化」のバックスラッシュを使うという原則になっています。この原則に従う限り、「特殊な/と単純な/」があった場合には単純な方に\を付けて\/とする必要があるわけです。

コードモードの場合

コードモードではバックスラッシュは有効な文字に含まれません。つまり、一般的にはバックスラッシュが含まれているとエラーが発生します。

(コードモード)
grid("A"\, "B", "C")
//==> ❌エラー: the character `\` is not valid in code

しかし、コードモードの中でも文字列リテラル"Hello\n"のようなstr値の即値の表記)については\を含めることができます。そこで以降では文字列リテラルでの\の用法を説明します。

文字列リテラルでの用法

  • 以下の組み合わせ(エスケープシーケンス)は特定の(直接入力が困難な)文字を表します。

    組み合わせ 符号位置 説明
    \\ U+005C バックスラッシュ「\」
    \" U+0022 ダブルクオート「"」
    \n U+000A 改行文字(LF)
    \r U+000D 復帰文字(CR)
    \t U+0009 タブ文字(HT)
  • \u{Unicodeエスケープを開始します。Unicodeエスケープの書式についてはマークアップモードと同じ規定と思っていいでしょう。

    文字列中のUnicodeエスケープはマークアップモードのものと比べて複雑な挙動を示します。マークアップモードではエラーになる不完全なUnicodeエスケープの入力に対してもエラーにならずに以下のように動作します。

    1. 直後に16進数字が続かない\u{はUnicodeエスケープの開始と見なされません。つまり\は特殊用法に該当しないのでそのまま\を表します。
    2. 閉じる}が欠落している場合(つまり\u{‹符号値16進数字列›の後に}がないパターン)は}がある場合と同様に扱われ、その符号値をもつUnicode文字を表します。

    1はともかく2はかなり不自然であり将来“修正”が入るかもしれません。現状の挙動には依拠せずに「マークアップモードでエラーになる書き方」は文字列リテラルでも使わないのが無難でしょう。

  • 上述の場合以外では、\そのまま\の文字を表します。例えば"\#"は文字通りで「\#」という文字列を表します。マークアップモードの\とは仕様が異なる5ので注意が必要です。

(コードモード)
// 文字列を符号値の列に変換する関数
let dump(s) = s.codepoints().map(str.to-unicode)

// エスケープシーケンスの例
dump("A\\\"\n\r\tB")
//==> (65, 92, 34, 10, 13, 9, 66)
// Unicodeエスケープの例
#dump("A\u{20000}B") \
//==> (65, 131072, 66)
// これはそのまま「A\*\a\xB」という文字列
#dump("A\*\a\xB") \
//==> (65, 92, 42, 92, 97, 92, 120, 66)
// これはそのまま「A\u42B」という文字列
#dump("A\u42B") 
//==> (65, 92, 117, 52, 50, 66)

余談: バックスラッシュだらけの文字列を簡単に扱う術

Typstのスクリプトにおいて「バックスラッシュを大量に含む文字列」を扱いたい場合があります。例えば正規表現パターンやWindowsのパス名を扱う場合6が該当します。

例えば「\[(\w+)\]:\s*(\d+)\n」という正規表現(regex値)を使いたいとします。するとこのパターンを文字列リテラルで書くことになります7が、\を大量に書く必要があり、これはいかにも面倒です。

(コードモード)
// これは面倒🤔
let rx = regex("\\[(\\w+)\\]:\\s*(\\d+)\\n")

この問題の解決策として、生テキスト`~`記法で表される文書要素)を利用する方法があります。ご存じの通り、`~`記法ならどんな文字でもそのまま書けます。生テキスト(rawエレメント)自体は文書要素(content値)であり文字列(str値)ではありませんが、「中身の文字列」を表すtextフィールドがあります。これを利用して、 `~`.textとすればの部分の文字列を取り出せます。

(コードモード)
// `~`.text は"~"に書いた文字列
let rx = regex(`\[(\w+)\]:\s*(\d+)\n`.text)
// 想定通りに動作する
"[answer]: 42\n".match(rx).captures
//==> ("answer", "42")

長い形式(```~```)の生テキストも利用できます。こちらの場合は開始の```の直後の改行が無視される8ので複数行にわたる文字列の記述に便利でしょう。

(コードモード)
// 複数行にわたる文字列データ
let data = csv(bytes(```
foo,42
bar,54
```.text))
// 想定通りに動作する
data.at(0)
//==> ("foo", "42")

実は、正規表現のパターンの場合は「余分の\を追加せずにそのまま"~"で囲って文字列リテラルにする」という方法でも問題なく動作します。

(コードモード)
// "~"の中にそのまま書く😐
let rx = regex("\[(\w+)\]:\s*(\d+)\n")
// それでも想定通りに動作する😲
"[answer]: 42\n".match(rx).captures
//==> ("answer", "42")

前節で述べた通り、Typstの文字列リテラルでは特殊な意味を持たない\はそのまま維持されるので、\[\wの部分はそのまま解釈されます。\nの部分は文字列のエスケープシーケンスなのでU+000Aの文字に置き換わりますが、正規表現で\nが表しているのもU+000Aの文字なのでパターンの意味に影響はありません。Typstの文字列リテラルで特殊な意味を持つ組み合わせ(\\\"\n\r\t\u{‹符号値›})は全てTypstの正規表現でも同じ意味をもつため、文字列リテラルの\の解釈で意味が変わることは決してないわけです。

まとめ

:neutral_face:「なんか、余談の方が分量が多くなっているぞ」(ざんねん:upside_down:

  1. マークアップテキストの末尾の\もこの項に含まれます。

  2. あるいはevalを使ってrepr(eval(mode:"markup", "A\\"))の結果を調べるという手もあります。ここでrepr[A\]では\]に付いていると見なされて失敗します。なお、例示コードでは最初の“BREAK”と“B”の間に空きが入っていて、これからも空白文字がそのまま残ることが確かめられます。

  3. 例では(x^2 - x y + y^2)のように添字付き文字に(~)を適用すると括弧が不必要に伸長することを示しました。これに対して、「それは単に\left(~\right)の記述を面倒がったLaTeX者が伸長させないだけで、本当は伸長する方が組版的に適切ではないか」と思った読者がいるかもしれません。そういう人は高校数学の教科書や参考書(LaTeX・Typstの組版でないもの)を見てみましょう。添字付き文字のケースでは括弧は伸長していないはずです。

  4. これは「伸長しない」と判断した括弧を全て\(~\)で書いた場合の話です。「そもそも伸長が起こらない場合は(~)で書く」という方針も可能ですが、これだと「伸長が起こるかどうか」もユーザが判断する必要が生じて面倒です。

  5. マークアップモードではほぼ全ての文字に対して\がリテラル化の機能を果たすのに対して、文字列リテラルでは「実際に文字列リテラル中で特殊な意味を持つ文字」である\"に対してのみ\がリテラル化の機能を果たす、といえます。

  6. あるいは「バックスラッシュを大量に書く組版ソフトウェア🍣」のコードをTypstで扱う場面があるかもしれません。

  7. Typstでは正規表現の値(regex値)はregex(‹パターン文字列›)のように文字列値(str値)から生成するため、一旦パターンを文字列値として表す必要があります。

  8. 長い形式の生テキストでは言語タグ(開始の```の直後に書く)が指定できます。文字列リテラル代用の用法では言語タグは意味を持ちませんが、```jsonのように指定しておくと一部の開発環境(Timymist等)では文字列の部分にハイライトが効きます。

4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?