現在我們已經知道,Swift的帶屬性字串(AttributedString)可以用來「標示」(markup)一篇文章,例如將其中一部分文字(子字串)作為標題、某些標示為內文、某些以斜體表示...等等。被標示過的文字可稱為 “rich text”(富文字 — 有豐富屬性的文字),例如微軟公司的 Word 軟體編輯出來的文件,副檔名可用 .RTF — 代表 Rich Text Format。

不止文書處理軟體,一般的網頁文字內容其實也都有編排過,其文字背後都有「標示」,而且還有專門的「標示語言」來做網頁編排的工作,這個「標示語言」稱為 HTML(HyperText Markup Language, 超文本標示語言),如果檔案副檔名為 .htm 或 .html,就是用 HTML 編排過的文件。

微軟的 .RTF 格式是該公司專有的標示格式,HTML 則是全球資訊網(WWW)的官方標準,除此之外,網路上還流行一種「民間版」的標示語言,稱為 “Markdown”(常用副檔名為 .md),在程式設計圈內非常普遍,例如最大的開放原始碼網站 GitHub,文件幾乎都用 Markdown 格式撰寫。

HTML 與 Markdown 文件格式都非常簡單,簡單到可直接用文字編輯軟體來手工編排,兩者標示方式相當接近,還可透過軟體互相轉換。部分的常見標示範例如下表:

- HTML Markdown
標題(heading) <h1>文件標題</h1>
<h2>次標題</h2>
<h3>小標題</h3> # 文件標題

次標題

小標題 |

| 斜體(italic) | <i>斜體文字</i> | 斜體文字 | | 粗體(bold) | <b>粗體文字</b> | 粗體文字 | | 刪除線(strikethrought) | <s>贅字應刪除</s> | 贅字應刪除 | | 加連結(anchor/hyperlink) | <a href=”網址”>連結文字</a> | 連結文字 | | 加圖片(image) | <img src=”網址”, alt=”圖說文字”> | 圖說文字 |

從上表可以看出,HTML 用一對「角括號」來標示文字;而Markdown則習慣用標點符號 — 這顯然符合程式設計師的喜好。

AttributedString 物件能夠讀入Markdown格式的文件,不過很可惜,目前並非所有Markdown格式都支援,包括標題、底線、圖片等常用標示都暫時不支援,或許未來新版才會加入(還可能支援HTML或RTF等格式),如果發展成熟,用AttributedString物件就能開發出一套文書編輯軟體。

在以下範例4-2c中,用Markdown語法將字串中的地名標示為粗體、「泰耶魯」加上維基百科連結、還有一小句用刪除線測試。

這是我們第一次用「多行字串」,過去我們都是用一對雙引號來包含字串值(String literal),如果字串值很大(跨很多行),可以前後用「連續3個雙引號」來包含字串值,請參考以下範例。

// 4-2c Markdown 標示語言
// Revised by Heman, 2022/03/22
import PlaygroundSupport
import SwiftUI

let 雪山輯 = """
    雪溶後 花香流過**司介欄溪**的森林
    沿著長長的狹谷 成團的白雲壅著
    獵人結伴攀向**司馬達克**去
    採菇者領著赤足的婦女
    在高寒的**賽蘭酒** 起一叢篝火
    
    修好所有的籬 結新的筏
    起得早早的小姑娘 在水邊洗日頭
    少年的[泰耶魯](<https://zh.wikipedia.org/wiki/%E6%B3%B0%E9%9B%85%E6%97%8F>)唱出冬藏的歌
    而卻不見了 ~~那著人議論的~~
    那浪子麻沁
    """

var 帶屬性字串 = try AttributedString(markdown: 雪山輯, options: AttributedString.MarkdownParsingOptions(interpretedSyntax: .inlineOnlyPreservingWhitespace))
let 圖片網址 = "<https://storage.googleapis.com/opinion-cms-cwg-tw/article/201905/article-5cd90f7b737c2.jpg>"

struct 現代詩選: View {
    let 動畫效果 = Animation.linear(duration: 12)
    @State var 位移: CGFloat = 500
    var body: some View {
        ZStack {
            AsyncImage(url: URL(string: 圖片網址)) { 狀態 in
                if let 背景圖片 = 狀態.image {
                    背景圖片.opacity(0.25)
                } else if 狀態.error != nil {
                    Image(systemName: "xmark.icloud.fill")
                        .scaleEffect(2)
                        .foregroundColor(.red)
                } else {
                    ProgressView()
                }
            }
            Text(帶屬性字串)
                .font(.system(.title))
                .offset(x: 0, y: 位移)
                .animation(動畫效果, value: 位移)
                .onAppear {
                    位移 = 0
                }
        }
    }
}

PlaygroundPage.current.setLiveView(現代詩選())

從範例可以看出,Markdown的標示符號直接寫在字串裡面,是資料的一部分,而不像AttributedString的屬性必須寫程式碼才能設定。這樣的好處之一,就是Markdown文件可以由編輯人員另外處理,再透過網路或檔案輸入到Swift程式裡面,程式設計師就不用管文件編排的事情。

要用AttributedString讀入Markdown格式的文字內容,就只需增加一個 markdown 參數: