改進《純數學教程(紀念版)》中的根式
人民郵電出版社圖靈公司準備重新出版《純數學教程(紀念版)》。我於 2013 年 10 月寫了一篇文章“《純數學教程(紀念版)》中的根式”,說:書中的根式裡面都有不必要的括號。
現在我們來去掉這些不必要的括號。這本書是使用 LaTeX 排版的,第 31 頁第 32 題的第 1 個根式的 TeX 程式碼如下:
\[
\sqrt {\left( {\sqrt[3]{5} - \sqrt[3]{4}} \right)} =
\frac{1}{3}\left( {\sqrt[3]{2} + \sqrt[3]{20} -
\sqrt[3]{{25}}}\right),
\]
去掉不必要的括號後變為:
\[
\sqrt { {\sqrt[3]{5} - \sqrt[3]{4}} } =
\frac{1}{3}\left( {\sqrt[3]{2} + \sqrt[3]{20} -
\sqrt[3]{{25}}}\right),
\]
第 2 個根式:
\[
\sqrt[\mbox{\raisebox{0.8ex}{\mbox{{\mbox{${}^3$}}}}}]{\left(
{\sqrt[3]{2} - 1} \right)}=
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{\left(
{\frac{1}{9}} \right)}-
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{\left(
{\frac{2}{9}} \right)}+
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{\left(
{\frac{4}{9}} \right)},
\]
去掉不必要的括號後變為:
\[
\sqrt[\mbox{\raisebox{0.8ex}{\mbox{{\mbox{${}^3$}}}}}]{
{\sqrt[3]{2} - 1} }=
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{
{\frac{1}{9}} }-
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{
{\frac{2}{9}} }+
\sqrt[\mbox{\raisebox{1.5ex}{\mbox{{\mbox{${}^3$}}}}}]{
{\frac{4}{9}} },
\]
我寫了一個 C# 程式來完成這個任務,執行結果如下:
$ mcs sqrttransformer.cs && ./sqrttransformer.exe
5 3 ../ch00.tex
273 41 ../ch01.tex
109 50 ../ch02.tex
58 34 ../ch03.tex
52 10 ../ch04.tex
53 36 ../ch05.tex
216 156 ../ch06.tex
70 61 ../ch07.tex
101 62 ../ch08.tex
112 75 ../ch09.tex
59 46 ../ch10.tex
7 7 ../ch99.tex
1115 581 Total
$
可以看出,全書共有 1115 個根式(包含巢狀的根式),其中有 581 個根式需要去掉不必要的括號。第 6 章需要去掉不必要的括號的根式最多,有 156 個。
源程式如下:
1 using System;
2 using System.IO;
3
4 static class SqrtTransformer
5 {
6 static readonly string S = "\\sqrt", L = "\\left", R = "\\right";
7 static readonly string[] Ls = {"(","[","\\{",L+"(",L+"[",L+"\\{"};
8 static readonly string[] Rs = {")","]","\\}",R+")",R+"]",R+"\\}"};
9 static int n1 = 0, n2 = 0;
10
11 static string DeleteBracket(string s)
12 {
13 if (s.Length < 5 || s[0] != '{' || s[s.Length - 1] != '}') return s;
14 var i0 = 1; while (char.IsWhiteSpace(s, i0)) i0++;
15 for (var k = 0; k < Ls.Length; k++) {
16 if (!s.Substring(i0).StartsWith(Ls[k])) continue;
17 var i1 = s.IndexOf(Rs[k], i0 += Ls[k].Length);
18 if (i1 < 0) throw new Exception("Right bracket not found");
19 var i2 = i1 + Rs[k].Length; while (char.IsWhiteSpace(s, i2)) i2++;
20 if (i2 + 1 != s.Length) return s; // right bracket isn't most right
21 return Transform("{" + s.Substring(i0, i1 - i0) + "}");
22 }
23 return s;
24 }
25
26 static (int Left, int Right) GetBoundary(string s, int i)
27 {
28 for (i += S.Length; char.IsWhiteSpace(s, i); ) i++;
29 if (s[i] == '[') { while (s[i] != ']') i++; i++; }
30 while (char.IsWhiteSpace(s, i)) i++; int i0;
31 if (s[i0 = i] != '{') return (i, i); //TODO: s[i] == '\\'
32 for (var n=1; n>0;) if (s[++i]=='{') n++; else if (s[i]=='}') n--;
33 return (i0, i); // s[i0] == '{' && s[i] == '}'
34 }
35
36 static string Transform(string s)
37 {
38 var t = new System.Text.StringBuilder();
39 for (int j, i = 0; i < s.Length; i++) {
40 if ((j = s.IndexOf(S, i)) < 0) { t.Append(s.Substring(i)); break; }
41 var (b, d) = GetBoundary(s, j); t.Append(s.Substring(i, b - i));
42 string s2, s1 = s.Substring(b, (i = d) - b + 1);
43 t.Append(s2 = DeleteBracket(s1)); n1++; if (s1 != s2) n2++;
44 }
45 return t.ToString();
46 }
47
48 static void Main()
49 {
50 int i1 = 0, i2 = 0;
51 foreach (var file in Directory.GetFiles("..", "ch??.tex")) {
52 File.WriteAllText(file, Transform(File.ReadAllText(file)));
53 Console.WriteLine("{0,4} {1,3} {2}", n1 - i1, n2 - i2, file);
54 i1 = n1; i2 = n2;
55 }
56 Console.WriteLine("{0,4} {1,3} Total", n1, n2);
57 }
58 }
簡要說明:
- 第 51 行的 foreach 迴圈遍歷全書各章(ch00.tex, ch01.tex, ...)。
- 第 52 行的 File.ReadAllText 方法把某一章全部讀入記憶體。
- 然後呼叫 Transform 方法進行轉換(去掉不必要的括號)。
- 接著呼叫 File.WriteAllText 方法把這一章寫回 ch??.tex 檔案。
- 第 36 至 46 行的 Transform 方法執行轉換。主要是查詢 "\sqrt",然後呼叫 GetBoundary 方法找出其後的以 '{' 和 '}' 表示的左右邊界,再去掉其中的不必要的括號。
- 第 26 至 34 行的 GetBoundary 方法尋找 "\sqrt" 的左右邊界。
- 第 29 行跳過 "[...]"(對應於開平方以外的情況)。
- 第 31 行對應被開方數是單個符號的情況。其中有可能是 \Delta 這樣用多個字元表示的單個符號,但是對我們的目的沒有影響,為簡單起見,直接定界為 \ 就行了。
- 第 32 行定界 "{...}" 的情況,其中允許有巢狀的 "{}"。
- 第 11 至 24 行的 DeleteBracket 方法刪除不必要的括號。
- 第 16 行判斷根式中是不是以左括號開頭。
- 第 17 行尋找匹配的右括號。
- 第 18 行處理找不到匹配的右括號的情況。
- 第 20 行處理右括號後面不是緊接著右邊界的情況,此時這對括號是必要的,不能刪除。
- 第 21 行遞迴呼叫 Transform 方法以刪除巢狀的根式中的不必要的括號。
如果需要正確處理被開方數是 \Delta 這樣的情況,可以把第 31 行替換為:
if (s[i0 = i] != '{') {
if (s[i] != '\\') return (i, i);
for (i0 = i++; char.IsLetter(s, i); ) i++;
return (i0, i - 1);
}
相關文章
- 人月神話(40週年中文紀念版)
- 我的創作紀念日
- 紀念二姨父!
- 紀念類自然數(lzrs)學派十君子之一:王綱強先生
- OMG !Gopher China 限量版紀念衫!他來了!Go
- 免費線上戀愛紀念日、結婚紀念日計算器
- 紀念小柴昌俊 | 中微子天體物理學的誕生
- win10純淨版系統中安裝沒有數字簽名驅動的教程Win10
- 合肥光源四十週年紀念
- 純粹的數學之美
- 紀念皮拉內西:探索遊戲中的無限之境遊戲
- 日本森紀念財團:2022年全球城市實力指數
- 紅米k30s至尊紀念版和小米10pro的區別
- 為慶祝週年紀念日,Win10版《我的世界》將支援OculusRiftWin10
- 紀念幣有沒有收藏價值
- 紀念碑谷2(8-14章)
- Focal Loss改進版 GFocal Loss
- 基於 Angular 開發的 紀念日計算工具Angular
- 紅米K30S至尊紀念版和opporeno4se引數對比 哪個更值得入手
- 11.4 - ? 改題紀要
- 2021成都車展:保時捷718 Boxster 25週年紀念版SMX
- 人民幣發行70週年紀念幣
- P5662 [CSP-J2019] 紀念品
- 第一個部落格,紀念一下
- 紀念DedeCMS創始人IT柏拉圖先生
- 粒子群演算法中對於學習因子的改進演算法
- 日本森紀念財團:2019年全球城市實力指數(GPCI)報告
- 數字多媒體紀念館設計案例,科技助力見證歷史!
- win10純淨版怎麼安裝步驟_windows10純淨版安裝教程Win10Windows
- 2021 年:普通平凡而有紀念意義的一年
- 影馳 20 週年 RTX 4070 紀念版 攜手DLSS 3“流暢”一整年
- shell的引數和指令碼流程改進指令碼
- 10.4 - 11.4 改題紀要
- 入園第一天,聊作紀念
- Numerator:2022年紀念日消費者調查
- 洛谷P1094 紀念品分組(Java)Java
- 本週大事記 | 9.18紀念日+安全播報
- 【翻譯】.NET 5中的效能改進