Chuẩn hoá Google Docs
创建于:2025年1月14日
创建于:2025年1月14日
Gathering URLs
I’m setting up a JavaScript program in Google Apps Script to collect Google Docs URLs from column A, starting from row 2 until the last non-empty row in "Trang tính1." The task involves reading the URLs to open and manipulate text in each document.
Capitalizing headers
Now I'm focusing on transforming "Tiêu đề 1" to "Title 1" by capitalizing the initial letter of each word, ensuring the rest of the words remain in lowercase.
Clarifying capitalization
I'm thinking about the phrase "viết hoa toàn bộ chữ cái đầu" and confirming that the user wants each word in "Tiêu đề 1" capitalized, not the entire header in uppercase.
Differentiation in capitalization
I’m mapping out the distinction between capitalizing all letters and just the initial ones, confirming "789Win" retains "789" in uppercase while "Win" remains in lowercase.
Standardizing headings
I'm working on formatting headings by making all letters lowercase except the initial one, while keeping brand names 789Win, V9Bet, Vin777, i9Bet, and 12Bet capitalized as shown.
Standardizing text
I’m refining the approach to ensure all text is in sentence case, with brand names correctly capitalized, and bolded non-heading text formatted properly. This maintains consistency and clarity throughout.
Streamlining brand names
I’m converting variant brand names to their standardized forms, ensuring consistency and clarity throughout the text, and enhancing the overall formatting to meet the specified requirements.
Mapping the function
I’m outlining a JavaScript function to fetch Google Docs URLs from Google Sheets, open them, and perform specific text transformations, including format adjustments and brand name standardization.
Mapping transformations
I’m outlining functions for standardizing headings to sentence case, capitalizing initial letters, and formatting bolded text. Brand name standardization ensures consistent application throughout.
Crafting the function
I’m piecing together a function to standardize brand names using regex patterns, ensuring consistent capitalization throughout the text, then incorporating bolded text transformation for completeness.
Formatting text
I’m finalizing the script, ensuring brand names are standardized using regex patterns, converting paragraphs to title case, and transforming bolded text as specified for each type of heading in Google Docs.
Finishing up the script
I’m wrapping up the Google Apps Script to standardize heading formatting, including title fromheading 1 and sentence fromheadings 2-4, ensuring bolded text is also properly formatted.
Parsing URLs
I’m refining the parseIdFromUrl
function to extract document IDs from Google Docs URLs. I’ll integrate this with the script to open and manipulate documents effectively.
Air-tight method
Ensuring brand names are mapped post-title case conversion, cautiously handling sequences like "789win" to accurately apply transformations without disrupting capitalization standards.
Crafting the approach
I'm mapping out toTitleCase before standardizing brand names, considering brand names with spaces or punctuation might need nuanced handling. For headings 2-4, sentence case is applied post brand name mapping.
Transforming and standardizing
I'm converting headings 2-4 to sentence case, standardizing brand names, and ensuring bolded text is formatted correctly, preserving capitalization after punctuation or at paragraph starts.
Formatting bold text
I’m mapping out a strategy to iterate over each bold text segment, converting it to lowercase and capitalizing the initial letter if it stands at the start of a sentence.
Refining text formatting
I’m thinking about identifying bold text, converting it to lowercase, capitalizing the initial letter post-punctuation, applying brand name standardization, and updating the text accordingly.
Navigating bold text
Considering whether to keep bold formatting while converting text to lowercase or to remove bold formatting entirely, based on the user's instructions. This balance will ensure clarity and consistency.
Adjusting text coverage
I’m tweaking the script to clarify formatting rules: keep bold text, convert it to lowercase, and capitalize the initial letter if it’s post-punctuation or at the paragraph's start.
Refining script logic
I'm noting changes to ensure bold text is lowercase, capitalizing the first letter if post-punctuation or paragraph start. Brand name standardization will follow.
Thought about Google Sheets script for text formatting cho 1m 34s
Dưới đây là một ví dụ mã Google Apps Script (JavaScript) chạy trong Google Sheet, thực hiện các bước theo yêu cầu của bạn. Mã này sẽ:
Lưu ý quan trọng:
- Để chạy được, bạn cần có quyền truy cập/chỉnh sửa các Google Docs tương ứng.
- Mã ví dụ này mang tính minh hoạ tương đối; tuỳ mức độ phức tạp của nội dung tài liệu, bạn có thể phải điều chỉnh thêm cho phù hợp (đặc biệt về cách tách câu, xử lý sau dấu chấm câu, v.v.).
- Khi dán mã vào Apps Script, bạn hãy lưu lại, sau đó chạy hàm
standardizeDocs()
.
/************************************ * 1. Hàm chính để chạy trên Google Sheet ************************************/ function standardizeDocs() { // Lấy sheet cần thao tác const sheetName = "Trang tính1"; const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName); if (!sheet) { SpreadsheetApp.getUi().alert(`Không tìm thấy sheet tên "${sheetName}".`); return; } // Xác định hàng cuối cùng có dữ liệu ở cột A const lastRow = sheet.getLastRow(); if (lastRow < 2) { SpreadsheetApp.getUi().alert("Không có dữ liệu URL trong cột A (hàng 2 trở đi)."); return; } // Đọc danh sách URL từ hàng 2 đến hàng cuối const data = sheet.getRange(2, 1, lastRow - 1, 1).getValues(); // Mảng chứa các quy tắc chuẩn hoá brand name const brandMappings = [ { regex: /789win/gi, replacement: "789Win" }, { regex: /v9bet/gi, replacement: "V9Bet" }, { regex: /vin777/gi, replacement: "Vin777" }, { regex: /i9bet/gi, replacement: "i9Bet" }, { regex: /12bet/gi, replacement: "12Bet" } ]; // Lặp qua từng URL for (let i = 0; i < data.length; i++) { const url = data[i][0]; if (!url) continue; // Bỏ qua ô trống // Tách docId từ đường dẫn URL const docId = parseDocIdFromUrl(url); if (!docId) { console.log(`Không trích xuất được docId từ URL: ${url}`); continue; } // Mở Doc theo docId let doc; try { doc = DocumentApp.openById(docId); } catch (e) { console.log(`Lỗi mở Google Docs ID = ${docId}: ${e}`); continue; } const body = doc.getBody(); const numChildren = body.getNumChildren(); // Duyệt qua tất cả phần tử (paragraph) trong Body for (let j = 0; j < numChildren; j++) { const child = body.getChild(j); if (child.getType() === DocumentApp.ElementType.PARAGRAPH) { const paragraph = child.asParagraph(); const heading = paragraph.getHeading(); // 3.1. Nếu là Heading 1 => Title Case toàn bộ if (heading === DocumentApp.ParagraphHeading.HEADING1) { let text = paragraph.getText(); // Bước 1: Chuyển sang Title Case text = toTitleCase(text); // Bước 2: Chuẩn hoá brand name text = standardizeBrandNames(text, brandMappings); // Gán lại text cho đoạn paragraph.setText(text); // 3.2. Nếu là Heading 2, 3, 4 => sentence case (chỉ hoa chữ đầu) + brand name } else if ( heading === DocumentApp.ParagraphHeading.HEADING2 || heading === DocumentApp.ParagraphHeading.HEADING3 || heading === DocumentApp.ParagraphHeading.HEADING4 ) { let text = paragraph.getText(); // Bước 1: Chuyển về viết thường, hoa chữ cái đầu toàn chuỗi text = toSentenceCase(text); // Bước 2: Chuẩn hoá brand name text = standardizeBrandNames(text, brandMappings); // Gán lại paragraph.setText(text); // 3.3. Nếu là đoạn văn thường => xử lý các phần in đậm bên trong } else { // Sử dụng editAsText() để thao tác từng ký tự const textElement = paragraph.editAsText(); handleBoldText(textElement, brandMappings); } } } // Lưu và đóng Doc doc.saveAndClose(); } SpreadsheetApp.getUi().alert("Hoàn tất xử lý các tài liệu được liệt kê trong sheet."); } /************************************ * 2. Hàm tách docId từ URL * Ví dụ URL: * https://docs.google.com/open?id=xxxx * https://docs.google.com/document/d/xxxx/edit ************************************/ function parseDocIdFromUrl(url) { // TH1: dạng ?id=xxxx let match = url.match(/[\?&]id=([^&]+)/); if (match && match[1]) return match[1]; // TH2: dạng /d/xxx/ match = url.match(/\/d\/([^/]+)/); if (match && match[1]) return match[1]; return null; } /************************************ * 3. Chuẩn hoá brand name * (Đưa các biến thể 789win => 789Win, v.v.) ************************************/ function standardizeBrandNames(text, brandMappings) { let result = text; brandMappings.forEach(mapping => { result = result.replace(mapping.regex, mapping.replacement); }); return result; } /************************************ * 4. Chuyển chuỗi sang Title Case * (Viết hoa ký tự đầu mỗi từ) ************************************/ function toTitleCase(str) { if (!str) return str; // Tách theo "từ" (\w\S*) và chuyển ký tự đầu sang hoa, còn lại sang thường. return str.replace(/\w\S*/g, function(txt){ return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); }); } /************************************ * 5. Chuyển chuỗi sang dạng: * - Tất cả về thường * - Chỉ hoa ký tự đầu cả chuỗi ************************************/ function toSentenceCase(str) { if (!str) return str; str = str.trim(); if (str.length === 0) return str; // hạ mọi thứ xuống thường let lower = str.toLowerCase(); // hoa ký tự đầu return lower.charAt(0).toUpperCase() + lower.slice(1); } /************************************ * 6. Xử lý phần in đậm trong đoạn văn thường: * - Text in đậm => chuyển sang viết thường * - Nếu đứng đầu câu hoặc sau dấu câu (., !, ?) => hoa chữ cái đầu * - Giữ nguyên định dạng in đậm (không bỏ bold) * - Cuối cùng chuẩn hoá brand name ************************************/ function handleBoldText(textElement, brandMappings) { const fullText = textElement.getText(); const len = fullText.length; let i = 0; while (i < len) { // Kiểm tra ký tự thứ i có in đậm không? if (textElement.isBold(i)) { // Tìm đến hết đoạn in đậm let start = i; while (i < len && textElement.isBold(i)) { i++; } // Lúc này [start, i-1] là đoạn in đậm const boldRange = textElement.getText().substring(start, i); // Xử lý text cho đoạn in đậm const preceding = textElement.getText().substring(0, start); let processed = processBoldSubstring(boldRange, preceding); // Chuẩn hoá brand name processed = standardizeBrandNames(processed, brandMappings); // Thay thế trong text textElement.deleteText(start, i - 1); textElement.insertText(start, processed); // Sau khi chèn lại, ta cần setBold cho đúng đoạn vừa chèn textElement.setBold(start, start + processed.length - 1, true); // Điều chỉnh biến đếm (vì đã xoá chèn text) const delta = processed.length - boldRange.length; i = start + processed.length; // Cập nhật độ dài chuỗi do thay đổi } else { i++; } } } /************************************ * 7. Hàm xử lý riêng cho đoạn in đậm * - Đưa về viết thường * - Nếu đứng sau dấu câu (., !, ?) hoặc đầu đoạn => hoa chữ đầu ************************************/ function processBoldSubstring(boldText, precedingText) { if (!boldText) return boldText; // Chuyển tất cả về thường let text = boldText.toLowerCase(); // Kiểm tra điều kiện hoa ký tự đầu (sau dấu câu hoặc đầu đoạn) // 1) Nếu start == 0 (tức là đoạn đầu paragraph) // 2) Nếu precedingText kết thúc bằng . ? ! hoặc xuống dòng const lastChar = precedingText.slice(-1); if (precedingText.length === 0 || /[.?!\n]/.test(lastChar)) { text = text.charAt(0).toUpperCase() + text.slice(1); } return text; }
standardizeDocs()
và bấm nút Run (Chạy).Bạn có thể tuỳ chỉnh thêm các chi tiết xử lý (như nhận diện câu, khoảng trắng, …) tuỳ tình huống thực tế. Chúc bạn thành công!
Drafting the script
I’m outlining a script to read Google Doc URLs from Excel, clear custom formatting, and reset elements to default styles. This involves fetching elements and adjusting their style attributes to defaults, like headings and normal text.
Manual formatting
I’m detailing manual formatting adjustments for each paragraph and text run, setting headings to default styles, and removing all text attributes to achieve consistent, default formatting.
Tweaking formatting
OK, let me see. Revisiting manual adjustments to ensure headings and text run formatting align with Google Docs' default styles, focusing on heading 1 and normal text.
Adjusting text attributes
I'm finalizing the script to clear local overrides from text attributes, ensuring paragraphs and text chunks revert to their default Google Docs styles, maintaining headings and reset formatting to default.
Scripting default styles
I’m detailing the script to read doc IDs from Excel, parse URLs, and iterate through elements, reverting paragraphs and headings to default styles. This involves managing formatting styles for clarity and consistency.
Thought about resetting document formatting cho 32 giây
Dưới đây là một ví dụ mã Google Apps Script (JavaScript) chạy trong Google Sheet để:
Lưu ý:
- Script này có thể cần quyền truy cập chỉnh sửa Docs. Bạn nhớ chấp thuận khi lần đầu chạy.
- Nếu tài liệu phức tạp (có ảnh, bảng, v.v.) thì cần xử lý đệ quy các phần tử. Mã dưới đây mang tính minh họa tổng quát. Bạn có thể tùy biến để phù hợp với nhu cầu riêng.
/** * Hàm chính để chạy trên Google Sheet * Đọc URL từ cột A của "Trang tính1" (từ hàng 2 đến hàng cuối), * rồi gọi hàm để chuyển về định dạng mặc định trong Google Docs. */ function resetDocsFormatting() { const sheetName = "Trang tính1"; const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName); if (!sheet) { SpreadsheetApp.getUi().alert(`Không tìm thấy sheet tên "${sheetName}".`); return; } const lastRow = sheet.getLastRow(); if (lastRow < 2) { SpreadsheetApp.getUi().alert("Không có dữ liệu URL trong cột A (bắt đầu từ hàng 2)."); return; } // Lấy dữ liệu URL (cột A), từ hàng 2 đến hàng cuối const data = sheet.getRange(2, 1, lastRow - 1, 1).getValues(); for (let i = 0; i < data.length; i++) { const url = data[i][0]; if (!url) continue; // Bỏ qua ô trống // Tách docId từ link (dạng ?id=hoặc /d/..) const docId = parseDocIdFromUrl(url); if (!docId) { console.log(`Không thể tách docId từ URL: ${url}`); continue; } // Mở Doc theo docId let doc; try { doc = DocumentApp.openById(docId); } catch (e) { console.log(`Lỗi mở Doc ID: ${docId} - ${e}`); continue; } // Gọi hàm xử lý chuyển về định dạng mặc định resetFormatting(doc); // Lưu và đóng doc.saveAndClose(); } SpreadsheetApp.getUi().alert("Hoàn tất chuyển định dạng các tài liệu về mặc định."); } /** * Hàm tách docId từ URL: * - Dạng: https://docs.google.com/open?id=xxxx * - Hoặc: https://docs.google.com/document/d/xxxx/edit */ function parseDocIdFromUrl(url) { let match = url.match(/[\?&]id=([^&]+)/); if (match && match[1]) return match[1]; match = url.match(/\/d\/([^/]+)/); if (match && match[1]) return match[1]; return null; } /** * Hàm "resetFormatting(doc)" duyệt toàn bộ nội dung trong "doc" * và đưa tất cả phần tử (paragraph, table, list...) về định dạng mặc định. */ function resetFormatting(doc) { const body = doc.getBody(); processChild(body); } /** * Hàm đệ quy: duyệt tất cả child elements trong body/section/table/list... * Tùy vào loại phần tử, ta xử lý khác nhau. */ function processChild(parent) { const numChildren = parent.getNumChildren(); for (let i = 0; i < numChildren; i++) { const child = parent.getChild(i); const type = child.getType(); switch (type) { case DocumentApp.ElementType.PARAGRAPH: { const paragraph = child.asParagraph(); // Gọi hàm xóa bỏ định dạng cục bộ, trả về định dạng mặc định resetParagraphFormatting(paragraph); break; } case DocumentApp.ElementType.LIST_ITEM: { const listItem = child.asListItem(); resetParagraphFormatting(listItem); break; } case DocumentApp.ElementType.TABLE: { const table = child.asTable(); // Duyệt tất cả row và cell của table for (let r = 0; r < table.getNumRows(); r++) { const row = table.getRow(r); for (let c = 0; c < row.getNumCells(); c++) { const cell = row.getCell(c); // Gọi đệ quy để xử lý nội dung bên trong cell (Paragraph, List, Table, v.v.) processChild(cell); } } break; } case DocumentApp.ElementType.TABLE_ROW: { // Trong table đã xử lý row -> cell. // (Dòng này có thể không cần, vì row.getCell() xử lý rồi) break; } case DocumentApp.ElementType.TEXT: { // TEXT hiếm khi đứng "độc lập" ngoài paragraph; // Thường ta xử lý TEXT trong resetParagraphFormatting(). break; } default: { // Các trường hợp khác (SECTION_BREAK, PAGE_BREAK, INLINE_IMAGE, ...), // tùy nhu cầu mà ta có thể thêm logic, hoặc bỏ qua. break; } } } } /** * Hàm resetParagraphFormatting(paragraph): * - Giữ nguyên cấp heading (nếu đang là HEADING1 thì vẫn là HEADING1) * - Xóa tất cả "local override" (font, size, bold, italic...) để * Google Docs dùng style mặc định. */ function resetParagraphFormatting(paragraph) { const heading = paragraph.getHeading(); // B1: thiết lập lại heading như cũ (nếu đang là heading1 => setHeading(HEADING1)). // Việc này để chắc chắn paragraph sẽ mang style của heading tương ứng. paragraph.setHeading(heading); // B2: Xóa mọi cài đặt cục bộ trên từng ký tự/text // Sử dụng editAsText() để duyệt và setAttributes(null) hoặc từng thuộc tính = null. const textElement = paragraph.editAsText(); const length = textElement.getText().length; // ta sẽ xóa bỏ toàn bộ định dạng (font, size, bold, italic, link, foreground color...) // bằng cách setAttributes(null) cho từng ký tự for (let k = 0; k < length; k++) { textElement.setBold(k, k, null); textElement.setItalic(k, k, null); textElement.setUnderline(k, k, null); textElement.setFontFamily(k, k, null); textElement.setFontSize(k, k, null); textElement.setLinkUrl(k, k, null); textElement.setForegroundColor(k, k, null); // Tùy chọn: setBackgroundColor(k, k, null) nếu muốn xóa màu nền } // Nếu muốn gọn hơn (nhưng đôi khi thiếu một số thuộc tính), // có thể xài textElement.setAttributes({}) cho cả đoạn, nhưng // setAttributes({}) cho một range vẫn chưa phải "remove local override" 100% // trong một số trường hợp. // Ta dùng cách set...null để chắc chắn xóa override. // B3: Tùy chọn - cũng có thể "tắt" bullet/numbering nếu muốn // if (paragraph.getListId()) { // paragraph.setListId(null); // } }
resetDocsFormatting
và bấm Run (Chạy).Lưu ý mở rộng
- Nếu Docs có các phần tử phức tạp (bảng, danh sách lồng nhau, ảnh, footnote, v.v.), bạn có thể cần mở rộng mã để duyệt đệ quy sâu hơn.
- Cách tiếp cận trên sẽ xóa hết cài đặt cục bộ (bold, font family, size...) và để Google Docs áp dụng style mặc định cho từng kiểu Heading/Normal.
- Trong một số trường hợp, vẫn có thể còn sót vài định dạng “cứng đầu” (như highlight, spacing). Bạn có thể thêm đoạn
setLineSpacing(...)
haysetSpacingBefore(...)
, v.v. theo nhu cầu.
Chúc bạn thành công!
Mapping the script
I’m planning a JS function for Google Sheets to read URLs from column A, standardize doc formatting, and apply bold to headings. It involves parsing docids, opening docs, and adjusting headline styles and capitalization.
Refining capitalization
I'm detailing a strategy to scan each paragraph or list item for patterns like ". " or ": ", using regex to capitalize the letter that follows these patterns.
Enhancing text clarity
I’m suggesting regex and callback functions for capitalization. For headings like "heading1", "heading2", and "heading3", I’ll apply bold to the entire paragraph, ensuring consistent formatting throughout.
Thought about text formatting and bold headers cho 18 giây
Dưới đây là ví dụ mã Google Apps Script (JavaScript) chạy trong Google Sheet, đáp ứng yêu cầu:
Lưu ý:
- Khi chạy lần đầu, Script yêu cầu quyền chỉnh sửa Docs. Hãy chấp thuận để tiếp tục.
- Sau khi chạy xong, hãy mở lại Docs để kiểm tra thay đổi.
- Nếu tài liệu phức tạp (có bảng, hình ảnh, danh sách lồng nhau…), bạn có thể cần mở rộng xử lý đệ quy.
/** * Hàm chính, gọi từ Google Sheet. * Đọc URL từ cột A của "Trang tính1" (từ hàng 2 -> hàng cuối). * Mở từng Docs và thực hiện các yêu cầu. */ function capitalizeAndBoldHeadings() { const sheetName = "Trang tính1"; const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(sheetName); if (!sheet) { SpreadsheetApp.getUi().alert(`Không tìm thấy sheet "${sheetName}".`); return; } const lastRow = sheet.getLastRow(); if (lastRow < 2) { SpreadsheetApp.getUi().alert("Không có dữ liệu URL trong cột A (hàng 2 trở đi)."); return; } // Lấy dữ liệu cột A (URL) từ hàng 2 -> hàng cuối const data = sheet.getRange(2, 1, lastRow - 1, 1).getValues(); // Lặp qua từng URL for (let i = 0; i < data.length; i++) { const url = data[i][0]; if (!url) continue; // bỏ qua ô trống // Tách docId từ URL const docId = parseDocIdFromUrl(url); if (!docId) { console.log(`Không thể tách docId từ URL: ${url}`); continue; } // Mở Google Docs let doc; try { doc = DocumentApp.openById(docId); } catch (e) { console.log(`Lỗi mở Doc ID ${docId}: ${e}`); continue; } // Gọi hàm xử lý chính processDocument(doc); // Lưu và đóng doc.saveAndClose(); } SpreadsheetApp.getUi().alert("Hoàn tất xử lý viết hoa và in đậm tiêu đề."); } /** * Tách docId từ URL dạng: * https://docs.google.com/open?id=xxxx * hoặc * https://docs.google.com/document/d/xxxx/edit */ function parseDocIdFromUrl(url) { // Dạng ?id=xxxx let match = url.match(/[\?&]id=([^&]+)/); if (match && match[1]) return match[1]; // Dạng /d/xxxx/ match = url.match(/\/d\/([^/]+)/); if (match && match[1]) return match[1]; return null; } /** * Xử lý văn bản trong tài liệu: * 1. Viết hoa ký tự đầu sau ". " hoặc ": " * 2. In đậm các thẻ tiêu đề 1, 2, 3 */ function processDocument(doc) { const body = doc.getBody(); const numChildren = body.getNumChildren(); for (let i = 0; i < numChildren; i++) { const child = body.getChild(i); if (child.getType() === DocumentApp.ElementType.PARAGRAPH) { const paragraph = child.asParagraph(); const heading = paragraph.getHeading(); // Lấy toàn bộ text của đoạn const textElement = paragraph.editAsText(); let text = textElement.getText(); // 1) Viết hoa ký tự đầu tiên sau dấu ". " hoặc ": " // Sử dụng regex thay thế dạng: ( [.:] )( {1,} )( [a-z] ) => uppercase cho group 3 text = text.replace(/([.:])(\s+)([a-z])/g, function(match, p1, p2, p3) { return p1 + p2 + p3.toUpperCase(); }); // Cập nhật lại đoạn textElement.setText(text); // 2) Nếu đoạn là Heading 1,2,3 => setBold(true) toàn bộ if ( heading === DocumentApp.ParagraphHeading.HEADING1 || heading === DocumentApp.ParagraphHeading.HEADING2 || heading === DocumentApp.ParagraphHeading.HEADING3 ) { textElement.setBold(true); } } // Nếu có LIST_ITEM, TABLE... tuỳ chỉnh thêm nếu cần } }
capitalizeAndBoldHeadings
và bấm Run (Chạy)..
hay :
được viết hoa**Bạn có thể điều chỉnh regex, hoặc mở rộng xử lý với LIST_ITEM, TABLE... nếu cần. Chúc bạn thành công!