Làm việc với dải ô được đặt tên

API Google Tài liệu cho phép bạn sử dụng dải ô được đặt tên để đơn giản hoá một số thao tác chỉnh sửa.

Khi tạo một dải ô được đặt tên, bạn sẽ xác định một phần của tài liệu mà bạn có thể tham chiếu sau. Chỉ mục của dải ô được đặt tên sẽ tự động cập nhật khi nội dung được thêm vào và xoá khỏi tài liệu. Điều này giúp đơn giản hoá cách bạn tìm văn bản để cập nhật trong tương lai, vì bạn không cần theo dõi các thay đổi về nội dung chỉnh sửa hoặc tìm kiếm trong tài liệu. Thay vào đó, bạn có thể lấy vị trí chỉnh sửa bằng cách đọc dải ô được đặt tên và sử dụng các chỉ mục của dải ô đó.

Ví dụ: giả sử bạn tạo một dải ô được đặt tên, trong đó chuỗi "product description" (nội dung mô tả sản phẩm) phải xuất hiện trong một tài liệu:

Thao tác này cho phép bạn thay thế nội dung mô tả: bạn chỉ cần lấy chỉ mục bắt đầu và kết thúc của phạm vi được đặt tên, sau đó cập nhật văn bản giữa các chỉ mục đó bằng nội dung mới.

Mã ví dụ sau đây cho biết cách bạn có thể triển khai một hàm trợ giúp để thay thế nội dung của một dải ô được đặt tên trong thẻ đầu tiên của tài liệu, trong đó dải ô được đặt tên trước đó được tạo bằng CreateNamedRangeRequest. Để thay thế các dải ô được đặt tên từ tất cả các thẻ, bạn có thể mở rộng mã này để lặp lại trên tất cả các thẻ. Hãy xem phần Làm việc với thẻ để biết thêm thông tin và mã mẫu.

Java

/** Replaces the text in existing named ranges. */
static void replaceNamedRange(Docs service, String documentId, String rangeName, String newText)
    throws IOException {
  // Fetch the document to determine the current indexes of the named ranges.
  Document document =
      service.documents().get(documentId).setIncludeTabsContent(true).execute();

  // Find the matching named ranges in the first tab of the document.
  NamedRanges namedRangeList =
      document.getTabs()[0].getDocumentTab().getNamedRanges().get(rangeName);
  if (namedRangeList == null) {
    throw new IllegalArgumentException("The named range is no longer present in the document.");
  }

  // Determine all the ranges of text to be removed, and at which indexes the replacement text
  // should be inserted.
  List<Range> allRanges = new ArrayList<>();
  Set<Integer> insertIndexes = new HashSet<>();
  for (NamedRange namedRange : namedRangeList.getNamedRanges()) {
    allRanges.addAll(namedRange.getRanges());
    insertIndexes.add(namedRange.getRanges().get(0).getStartIndex());
  }

  // Sort the list of ranges by startIndex, in descending order.
  allRanges.sort(Comparator.comparing(Range::getStartIndex).reversed());

  // Create a sequence of requests for each range.
  List<Request> requests = new ArrayList<>();
  for (Range range : allRanges) {
    // Delete all the content in the existing range.
    requests.add(
        new Request().setDeleteContentRange(new DeleteContentRangeRequest().setRange(range)));

    if (insertIndexes.contains(range.getStartIndex())) {
      // Insert the replacement text.
      requests.add(
          new Request()
              .setInsertText(
                  new InsertTextRequest()
                      .setLocation(
                          new Location()
                              .setSegmentId(range.getSegmentId())
                              .setIndex(range.getStartIndex())
                              .setTabId(range.getTabId()))
                      .setText(newText)));

      // Re-create the named range on the new text.
      requests.add(
          new Request()
              .setCreateNamedRange(
                  new CreateNamedRangeRequest()
                      .setName(rangeName)
                      .setRange(
                          new Range()
                              .setSegmentId(range.getSegmentId())
                              .setStartIndex(range.getStartIndex())
                              .setEndIndex(range.getStartIndex() + newText.length())
                              .setTabId(range.getTabId()))));
    }
  }

  // Make a batchUpdate request to apply the changes, ensuring the document hasn't changed since
  // we fetched it.
  BatchUpdateDocumentRequest batchUpdateRequest =
      new BatchUpdateDocumentRequest()
          .setRequests(requests)
          .setWriteControl(new WriteControl().setRequiredRevisionId(document.getRevisionId()));
  service.documents().batchUpdate(documentId, batchUpdateRequest).execute();
}

Python

def replace_named_range(service, document_id, range_name, new_text):
    """Replaces the text in existing named ranges."""

    # Determine the length of the replacement text, as UTF-16 code units.
    # https://developers.google.com/docs/api/concepts/structure#start_and_end_index
    new_text_len = len(new_text.encode('utf-16-le')) / 2

    # Fetch the document to determine the current indexes of the named ranges.
    document = (
        service.documents()
        .get(documentId=document_id, includeTabsContent=True)
        .execute()
    )

    # Find the matching named ranges in the first tab of the document.
    named_range_list = (
        document.get('tabs')[0]
        .get('documentTab')
        .get('namedRanges', {})
        .get(range_name)
    )
    if not named_range_list:
        raise Exception('The named range is no longer present in the document.')

    # Determine all the ranges of text to be removed, and at which indices the
    # replacement text should be inserted.
    all_ranges = []
    insert_at = {}
    for named_range in named_range_list.get('namedRanges'):
        ranges = named_range.get('ranges')
        all_ranges.extend(ranges)
        # Most named ranges only contain one range of text, but it's possible
        # for it to be split into multiple ranges by user edits in the document.
        # The replacement text should only be inserted at the start of the first
        # range.
        insert_at[ranges[0].get('startIndex')] = True

    # Sort the list of ranges by startIndex, in descending order.
    all_ranges.sort(key=lambda r: r.get('startIndex'), reverse=True)

    # Create a sequence of requests for each range.
    requests = []
    for r in all_ranges:
        # Delete all the content in the existing range.
        requests.append({
            'deleteContentRange': {
                'range': r
            }
        })

        segment_id = r.get('segmentId')
        start = r.get('startIndex')
        tab_id = r.get('tabId')
        if insert_at[start]:
            # Insert the replacement text.
            requests.append({
                'insertText': {
                    'location': {
                        'segmentId': segment_id,
                        'index': start,
                        'tabId': tab_id
                    },
                    'text': new_text
                }
            })
            # Re-create the named range on the new text.
            requests.append({
                'createNamedRange': {
                    'name': range_name,
                    'range': {
                        'segmentId': segment_id,
                        'startIndex': start,
                        'endIndex': start + new_text_len,
                        'tabId': tab_id
                    }
                }
            })

    # Make a batchUpdate request to apply the changes, ensuring the document
    # hasn't changed since we fetched it.
    body = {
        'requests': requests,
        'writeControl': {
            'requiredRevisionId': document.get('revisionId')
        }
    }
    service.documents().batchUpdate(documentId=document_id, body=body).execute()

Xin lưu ý rằng dải ô được đặt tên chỉ định một dải ô nội dung tài liệu, nhưng không phải là một phần của nội dung đó. Nếu bạn trích xuất nội dung có chứa một dải ô được đặt tên, sau đó chèn nội dung đó vào một vị trí khác, thì dải ô được đặt tên chỉ trỏ đến nội dung ban đầu chứ không phải phần nội dung trùng lặp.