Mit benannten Bereichen arbeiten

Mit der Google Docs API können Sie benannte Bereiche verwenden, um einige Bearbeitungsaufgaben zu vereinfachen.

Wenn Sie einen benannten Bereich erstellen, geben Sie einen Abschnitt des Dokuments an, auf den Sie später verweisen können. Die Indexe des benannten Bereichs werden automatisch aktualisiert, wenn dem Dokument Inhalte hinzugefügt oder daraus entfernt werden. Dies vereinfacht das Auffinden von Text, der später aktualisiert werden soll, da Sie die Bearbeitungsänderungen nicht verfolgen oder das Dokument durchsuchen müssen. Stattdessen können Sie einen Bearbeitungsspeicherort abrufen, indem Sie den benannten Bereich lesen und dessen Indexe verwenden.

Angenommen, Sie erstellen einen benannten Bereich, in dem ein String für eine Produktbeschreibung in einem Dokument enthalten sein muss:

So können Sie die Beschreibung ersetzen: Sie rufen einfach die Start- und Endindexe des benannten Bereichs ab und aktualisieren dann den Text zwischen diesen Indexen mit dem neuen Inhalt.

Der folgende Beispielcode zeigt, wie Sie eine Hilfsfunktion implementieren können, um Inhalte eines benannten Bereichs zu ersetzen, bei dem der benannte Bereich zuvor mit CreateNamedRangeRequest erstellt wurde.

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).execute();

    // Find the matching named ranges.
    NamedRanges namedRangeList = document.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()))
                        .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()))));
      }
    }

    // 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).execute()

    # Find the matching named ranges.
    named_range_list = document.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')
        if insert_at[start]:
            # Insert the replacement text.
            requests.append({
                'insertText': {
                    'location': {
                        'segmentId': segment_id,
                        'index': start
                    },
                    '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
                    }
                }
            })

    # 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()

Beachten Sie, dass benannte Bereiche einen Bereich des Dokumentinhalts angeben, aber nicht Teil dieses Inhalts sind. Wenn Sie Inhalte extrahieren, die einen benannten Bereich enthalten, und ihn dann an einer anderen Stelle einfügen, verweist der benannte Bereich nur auf den ursprünglichen Inhalt und nicht auf den duplizierten Abschnitt.