要怎麽抓出文件中的特定文字或段落,直接改字体的大小、颜色、背景、粗细与字型?先来看今天的结果之一,把文章中的「人」字都改成红字、粗体与放大——
今天,我们会教用 GAS 搭配 Goolge Doc 来设定,这个要动用到的元素叫做 Attribute
。那因为在 Google Slide 中的 Element、Attribute 也很多有重叠,所以这边就会讲细一点,之後就可以一起服用。换句话说,今天会教说怎麽透过 GAS 调整 Google Doc 和 Google Slide 里面元素的「格式」。我们先复习一下前几天讲过的议题——
那今天,我们会针对上述议题中的「元素」进行。基本上前几天讲了上述元素的操作,今天终於可以进入到「格式调整」了,今天会专注在以下内容——
就让我们开始吧!
考虑到有些夥伴不一定会都有细读的文章,就捞叨一点把基本步骤再次附上,如果会的夥伴可以直接跳到 Q5。
我们已经知道大致上,每一个 Google 文件都会有 Element (元件),且每一个 Element 都会有 Attribute (属性)。今天我们主要会介绍下图绿色的 Attribute 的部分。
下图主要是列举几个常见用於操作 Element 的 Attribute。
这边就节录一本书中的「段落、照片、表格与清单」,来作为今天我们的范例。
好,大致理解基本概念後,就让我们开始吧。
那这次我们不会用 Google Sheet,而是直接用 Google Doc 进入,借一下 D16 的影片。
一样第一次会有存取验证需要大家按一下。这边仍是借用一下 D2 的影片。
getBody()
我们先用 getActiveDocument()
抓出正在绑定的文件;那假设我们都是针对主要内文(Body)的部分,所以我们先设定好 getbody()
。
let doc_body = DocumentApp.getActiveDocument().getBody();
因为更新有比较复杂的细节,我们就先来讲讲删除。
基本上之後的步骤会分成:
getAttributes()
)setAttributes()
)3-1 和 3-2 主要就是 D16 Element 的读取与创造 的涵盖内容,这边就一样快速带给大家看。
这边就先上一段「读取」的程序码——
function readParagraph(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let paragraphs = doc_body.getParagraphs();
Logger.log(paragraphs)
}
再来看读取的结果影片——
那如果要改成读取其他的 Element,可以参考之前的简易表单来做更换。
那如果我们今天要新增一段表格,可以怎麽做?我们可以运用 appendTable
的功能来执行。
function addTable(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let cells = [[1,2,3],[4,5,6]];
doc_body.appendTable(cells)
}
跑起来长这样——
那如果要改成新增其他的 Element,可以参考之前的简易表单来做操作。
那以上这边如果觉得太快,或想知道更细部,记得可以回去看 D16 Element 的读取与创造 ,如果觉得时间OK,那我们就进入到新的部分,也就是「部分读取」。
比起整段做读取、更改,我们更常遇到的情况是只要更动部分。像是我想要把文件中的关键字抓出来标记颜色等、或是想要动从第三页到第八页的表格,详细要怎麽执行?
基本上第一部,我们都要先跟 GAS 说「我想抓出元素的___部分」。而这边就要用 findText()
来执行。
findText()
的基本使用架构如下,我们用来示范如何抓到段落中的「人」字。
function testFindText(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let target = '人';
let searchResult = doc_body.findText(target);
while (searchResult !== null) {
Logger.log(searchResult.getElement().asText().getText());
searchResult = doc_body.findText(target, searchResult);
}
}
用法上, findText(searchPattern, from)
前面的 searchPattern 用的是 regex(严格说起来是 google 的 re2),我们就简单输入要找的文字;後面的 from
指的是当找到多个元素後,从哪一个开始?没输入的话预设会回传第一个,但在第一个之後如果要继续找,就要搭配 while
回圈并将 from
输入为前一次的搜寻结果。换句话说,就是把下图手刻的方式转成 while 回圈。
跑起来结果长这样——
那,从清单的只有回传两点发现,它确实有抓到「人」字,但是是回传了「人」字所在的整个元件(Element),如果是在段落(Paragraph)内,就回传段落,如果是在清单项目(ListItem)内就回传整个项目。那我们要怎麽抓出特定范围?这时就要提到 range
元素了。
range
元素与 offset
的概念Range 是什麽?简单来说,当我们用滑鼠选取了一段内容後,都会伴随出range
(当然省略掉 select
的部分,不过在这边我们先注重在 range
)。
且每个 range 都有被伴随的 offset(位移),简单来说可以当成:是在段落中的哪个位置。
以上面的影片来说,「人」这个字即是位在第四个位置(Offset 为 3);更严格地说,「人」这个 range
的在段落中的开始位置(StartOffset
) 和结束位置(EndOffset
)都是为在 Offset 为 3的部分。
注意因为是程序语言,第一个位置我们要从 Offset 为 0 开始算。位移的概念可以参考如下
那为什麽这个重要?因为当我们等下要改内容时,这就会派上用场。实际上,对 GAS 来说,「部分选取」就是先选整段,再跟我说段落中的哪个位置(Offset)要改。我们快速示范如果要将 Offset 的文字都改成红色要怎麽做。
我们先来看看没上 Offset 的结果,会发现就等於整段改成红色。
同时看看上了 Offset 的结果,会发现只有我们要的「特定范围」变色。
实际上,我是透过 range
物件中的 getStartOffset()
和 getEndOffsetInclusive()
达到的。先附上程序码,可以先专注看「Offset」的部分,我们马上就会来细讲改颜色的部分。
function highlightText() {
let target = '人';
let doc_body = DocumentApp.getActiveDocument().getBody();
let searchResult = doc_body.findText(target);
let textStyle={};
textStyle[DocumentApp.Attribute.FOREGROUND_COLOR] = '#FF0000'
while (searchResult !== null) {
let search_text = searchResult.getElement();
Logger.log(searchResult.getStartOffset() +' '+ searchResult.getEndOffsetInclusive())
search_text.setAttributes(searchResult.getStartOffset(), searchResult.getEndOffsetInclusive(),textStyle)
searchResult = doc_body.findText(target, searchResult);
}
好,那我们能抓到范围了,接下来就是要改属性了。但在改属性前,因为物件的属性算有点复杂,我个人是会建议先检查「有没有这个属性」。
getAttributes()
来读取现有属性通常我会先用 getAttributes()
来看我的目标物件有哪些可以调整的属性。这也可以帮助我们理解怎麽设定属性。这边写一段简单的程序,会印出目标「段落」、「清单项目」和「文件」的含有属性。
function testFindText(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let target = '人';
let searchResult = doc_body.findText(target);
while (searchResult !== null) {
Logger.log(searchResult.getElement().asText().getText());
Logger.log(searchResult.getElement().getAttributes());
searchResult = doc_body.findText(target, searchResult);
}
Logger.log(doc_body.getAttributes())
}
跑起来长这样——
我这边把「段落」、「清单项目」与「文件」分开来看。
{STRIKETHROUGH=null, LINK_URL=null, FONT_FAMILY=Source Sans Pro, FONT_SIZE=null, UNDERLINE=null, BACKGROUND_COLOR=null, ITALIC=null, FOREGROUND_COLOR=null, BOLD=null}
{LINK_URL=null, FOREGROUND_COLOR=null, BOLD=null, BACKGROUND_COLOR=null, UNDERLINE=null, STRIKETHROUGH=null, FONT_FAMILY=Source Sans Pro, FONT_SIZE=null, ITALIC=null}
{MARGIN_TOP=21.25984251968504, LINK_URL=null, FONT_SIZE=null, UNDERLINE=null, STRIKETHROUGH=null, FOREGROUND_COLOR=null, FONT_FAMILY=null, BOLD=null, PAGE_HEIGHT=841.68, MARGIN_BOTTOM=72.0, MARGIN_LEFT=72.0, BACKGROUND_COLOR=null, PAGE_WIDTH=595.4399999999999, ITALIC=null, MARGIN_RIGHT=72.0}
这边要特别提一下我们抓出的资料结构,是一种叫做 dictionary 的结构。这边的重点会放在,所以如果我们要写入「属性」,我们也要套用这结构。
而其中的属性有三种特性——
特别把第一点拉出来说明,因为待会会用到这概念。
setAttributes()
更改现有属性好,那到底要怎麽改属性呢?我们先来一段程序码。
function setElementAttribute(){
let doc_body = DocumentApp.getActiveDocument().getBody();
let style = {};
style[DocumentApp.Attribute.FOREGROUND_COLOR] = '#FF0000'
let paragraphs = doc_body.getParagraphs();
for(para of paragraphs){
para.setAttributes(style);
}
}
跑起来长这样——
这边先设定一个 dictionary 叫做 style
(let style = {}
),并用 style[key]=value
设定期中的数值(精确来说是 Key-value pair),其中 key
的部分就是我们从 Step 4 中抓出来的属性们,只是前面多加了 DocumentApp.Attribute
;数值就是 Step 4 的数值们。
可以发现,就是将所有「段落」都改成红色。至於为什麽「清单」也会变色,复习是因为清单内的文字,其实也有包含一个段落的元素。好,那这是整段的更改,基本上就是要全部元素取得後,针对一个个元素抓出来设定。
那如果我们想做部分文字的更改呢?这边就可以用我们在 Step 3 最後面的段落,先贴上方便大家比较。
function highlightText() {
let target = '人';
let doc_body = DocumentApp.getActiveDocument().getBody();
let searchResult = doc_body.findText(target);
let textStyle={};
textStyle[DocumentApp.Attribute.FOREGROUND_COLOR] = '#FF0000'
while (searchResult !== null) {
let search_text = searchResult.getElement();
Logger.log(searchResult.getStartOffset() +' '+ searchResult.getEndOffsetInclusive())
search_text.setAttributes(searchResult.getStartOffset(), searchResult.getEndOffsetInclusive(),textStyle)
searchResult = doc_body.findText(target, searchResult);
}
基本上就是要在 setAttributes()
前加上「起始」与「结束」的 Offset,跑起来长这样。
好,那我们介绍了「单纯改字体颜色」,如果我们想调整的很多,要怎麽办?没问题的,这边直接上程序码,用「部分元素」做示范。
function highlightText() {
// target,background
let target = '人';
let doc_body = DocumentApp.getActiveDocument().getBody();
let searchResult = doc_body.findText(target);
let textStyle={};
textStyle[DocumentApp.Attribute.FOREGROUND_COLOR] = '#FF0000'
textStyle[DocumentApp.Attribute.FONT_FAMILY] = 'Calibri';
textStyle[DocumentApp.Attribute.FONT_SIZE] = 18;
textStyle[DocumentApp.Attribute.BOLD] = true;
while (searchResult !== null) {
let search_text = searchResult.getElement();
search_text.setAttributes(searchResult.getStartOffset(), searchResult.getEndOffsetInclusive(),textStyle)
searchResult = doc_body.findText(target, searchResult);
}
}
跑起来长这样,确定我们有改到「人」字的颜色、字体与粗体——
但如果想设定其他的参数呢?这边直接帮大家整理了表格。首先,如果是要改「部分文字」,可以用以下的功能们。
如果是要改「整个段落」,可以用以下的功能们。
如果是要改「文字」以外的部分,可以参考官方文件。
好,那这边就是我们今天的内容。我有参考这篇:Can I color certain words in Google Document using Google Apps Script?,如果有夥伴想将上述功能改成有 UI 的 Add-On,里面有完整的程序码。另外,官方也有文件说明 Editing and styling text,也可以搭配参考。
好,那今天就到这边。今天我们主要交代了 Attribute 的「如何更新」,总算把 Document 的部分告一段落,明天会进入 Slide 的部分,最後会讲 Sheet。如果还有问题,透过留言之外,也可以到 Facebook Group,想开很久这次铁人赛才真的开起来,欢迎来当 Founding Member。如果不想错过可以订阅按赞小铃铛(?),也欢迎留言跟我说你还想知道什麽做法/主题。我们明天见。
看完这篇文章你会得到的成果图 之前内容的重点复习 (前情提要) 我们接下来的讨论,会基於读者已经先读...
来部落格看图文并茂文章 补觉鸣诗 时间回到我入行第二年 这时才算是正式的系统工程师并开机接触机房 最...
其实我原本是打算 docker 跟 k8s 各暂一半篇幅的 ... 但 docker 看着看着 .....
前情提要: 看完记忆体储存差异,现在要来谈谈全域污染这件事。 基本scope概念 所谓的范畴Scop...
最近有朋友回中国内地工作,刚好问我有什麽VPN推荐一下给他,需要在内地能翻墙,连脸书就可以了,了解他...