科技 · 實用指南
Google 表單多選答案含逗號:找回準確的已選項目
在表單原生 CSV 與原始回覆陣列之間選擇合適路徑,先核對每個已選標籤,再篩選或計數。

如果 Google 表單的多選回覆被拆成錯誤的任務,或統計結果令人懷疑,先檢查這些選擇如何進入試算表。一個以逗號串接的儲存格,可能掩蓋兩個選項之間的邊界,也可能把選項本身的標點混在其中。再加一條拆分規則,即使得到整齊的表格,含義仍可能錯誤。
先從表單本身下載 CSV,檢查檔案實際採用的表示方式。如果分隔符號無法保留你需要區分的資訊,就回到原始回覆陣列。目標是為每次提交取得一份準確的已選標籤清單;原始資訊已經無法取得時,也要明確知道何時應停止還原。
修改試算表前,先核對一份原始提交
以編輯者身分開啟原始表單,進入 Responses → Individual,逐份查看提交內容。挑一份已選標籤含有逗號的回覆,記下完整選項。如果表單存在 Email 與 Email newsletter 這類文字重疊的標籤,也找一份相關回覆。這樣就有原始依據,可與即將建立的表格比較。測試時使用副本,保留現有匯出檔。
確認實際題型。本文討論一般核取方塊題,也就是同一問題可以選擇多個選項。核取方塊方格帶有列結構,陣列形狀也不同。同時確認你需要各選項的次數、包含某選項的提交清單,還是視覺化摘要。如果 Forms 現有的摘要已能回答問題,匯出可能只是增加工作。
撰寫自訂匯出前,先試表單原生 CSV
在表單本身依序選擇 Responses → More → Download responses (.csv)。這與將連結的 Google 試算表下載成 CSV 是不同路徑。Displayr 於 2026 年 2 月更新的整合文件,將原生下載中的多選值描述為以分號分隔;Stack Overflow 上既有回答也提到這項差異。因此,標籤中有逗號,並不代表原生檔案一定無法使用。
先以能正確解析 CSV 的讀取器處理外層檔案,再檢查那份已知提交的多選欄位。CSV 欄位外面的引號保護的是整個欄位;單憑這層引號,無法確定欄位內多個選項的編碼方式。請確認實際檔案的內部分隔符號與跳脫規則。採用拆分規則前,測試包含該分隔符號的標籤,以及自由填寫的 Other 答案。如果拆出的完整選項與原始回覆一致,就採用這條較簡單的路徑。不要只因連結的試算表看起來難以處理,就用指令碼取代已經正確的匯出。如果任意填寫的 Other 文字可能包含該分隔符號,而你又無法確認可靠的跳脫規則,應使用原始陣列。
理解拆分與文字搜尋為何可能產生不同錯誤
假設允許的四個標籤是 ["A", "A, B", "B, C", "C"]。選擇 ["A, B", "C"] 與選擇 ["A", "B, C"],以逗號加空格串接後,都會變成 A, B, C。即使知道完整選項清單,也無法在這兩個結果之間判斷。這是人工建立的資料表示範例,並不是說 Google 的每一種匯出格式都有相同問題。
文字搜尋會造成另一類錯誤。如果實際選擇是 ["Email newsletter", "Food, drinks"],在串接後的字串中搜尋 Email,就會把未選取的選項也計入。若先按逗號加空格拆分,再以完整值比對,又會遺漏 Food, drinks。我們在本機實際執行了這兩個反例。實際處理時應先確定選項邊界,再計數;在子字串比對與拆分之間切換,本身無法證明邊界正確。
從原始表單重新取得已選值陣列
Google 的 Apps Script 參考文件規定,一般 CheckboxItem 的回覆是包含已選項目的 String[]。Stack Overflow 上已有完整範例:讀取 getResponses(),逐一處理每份回覆的 getItemResponses(),篩選 CHECKBOX 題,再呼叫 getResponse()。使用 Apps Script 時,從表單的 More → Apps Script 選單進入,讓指令碼綁定至該表單;執行需要編輯權限。文末列出這份完整範例,Google 也提供對應 API 方法的文件。
在該核取方塊迴圈中,保留 itemResponse.getResponse() 傳回的陣列。將 values 當作陣列處理前,先以 Array.isArray(values) 檢查;需要能保留每個字串邊界的文字表示時,使用 JSON.stringify(values)。先將陣列串接成一般文字,之後再嘗試拆開,會破壞這個目的。將回覆 ID 和題目 ID 與值一起保存;題目標題只是標籤,題目位置也是另一項屬性。Google 也說明核取方塊陣列的順序可能變動,因此不能將它解讀為使用者點選選項的先後順序。
需要結構化分頁資料時,使用官方回覆 API
Forms REST API 提供另一條有文件依據的路徑,不必自訂欄位內的分隔符號。在官方 forms.responses.list 參考頁面開啟 Try it,使用有權讀取該表單回覆的帳戶,填入表單編輯網址中的表單 ID。保存傳回的 JSON 回覆資料,不要將 OAuth 權杖或要求標頭當作回覆內容複製。另一個 forms.get 方法可取得表單定義,協助你找到核取方塊題的 questionId。
對於該題,每個已選值在 textAnswers.answers 中都是獨立項目。將 responseId、questionId 對應關係和表單 ID 與保存的每頁資料放在一起;list 方法不會在每個傳回的回覆物件中重複提供 formId。這些 REST 題目 ID 屬於該 API 的資料模型,不能拿另一份 Apps Script 匯出中的題目 ID 替代。
第一次要求成功,並不能證明已完整匯出。只要存在 nextPageToken,就使用該權杖、同一個表單及相同篩選條件要求下一頁,直到回傳內容不再包含它。pageSize 指定的是上限,服務可能傳回較少回覆。保留每一頁,並檢查相異的回覆 ID,之後才能將這批資料視為完整。本文沒有聲稱實際匯出了登入帳戶中的資料,也沒有聲稱這些要求構成在同一時刻凍結的交易快照。
以完整值判斷是否選取,並單獨處理缺少的答案
一般核取方塊答案已經是陣列時,values.includes("Food, drinks") 判斷的是有沒有選取這個完整標籤,不會比對另一個標籤中的部分文字。在 REST 表示中,先對指定題目答案的 textAnswers.answers 使用 .map(x => x.value) 取得字串,再做相同的完整值判斷。針對一個標籤,每次提交最多計算一次;不要將一份多選回覆算成數個不同的人。
缺少答案的情況需要另外處理。Apps Script 會從 getItemResponses() 省略這類未回答題目,因此依陣列位置配對,可能把後面的答案連到錯誤問題。應按元素或題目 ID 配對。將缺少的核取方塊答案與明確選取區分,並仔細決定百分比的分母:答案缺少本身無法說明該題是被略過、被分支繞過,還是後來才加入。這些匯出也無法恢復已刪除的歷史題目定義。
核對實際選擇,不能只看總列數
將原始提交中的完整標籤,與重新取得的陣列或解析後的原生 CSV 欄位逐一比較。檢查含標點的標籤、文字被較長標籤包含的短標籤、表單允許時的自由文字值,以及一道未回答的選填題。接著透過完整值判斷,核實一個已選標籤和一個未選標籤的次數。總列數正確,仍可能伴隨列內選擇內容錯誤。
我們實際執行的十項 Node 24.22.1 本機斷言,涵蓋分隔符號碰撞、兩種計數錯誤、UTF-8 JSON 往返、獨立題目 ID、缺少題目與安全的文字處理。測試使用符合 Forms 文件物件形狀的本機範例,未實際執行 Google Forms、Apps Script 授權、線上 CSV 匯出或登入帳戶中的 API Explorer。對於仍持續接收回覆的表單,應記錄匯出時間或選定的回覆範圍,並在比較總數前考量新提交的影響。
只剩有歧義的儲存格時,保留不確定性
原始表單回覆已無法取得時,已知的選項清單有時能確定唯一解讀,但不能保證如此:A, B, C 範例就有兩種合法選擇。Other 自由文字會使「某個分隔符號不會出現在值中」的假設格外脆弱。將尚未確定的儲存格標記為待複核,並請擁有者提供原始回覆,或另一份能驗證邊界的匯出。
資訊被攤平成字串後,再把逗號改成分號,無法復原已經遺失的資訊;替整個儲存格加引號也是如此。保留來源檔案,以及經認可的轉換所依賴的假設。在以結果分派工作或報告次數之前,應取得可追溯的準確已選值集合,或明確標出仍未解決的紀錄。
