如何使用搜索和替换通过 API 修改 Google Docs 文档?

How to MODIFY a Google Docs document via API using search-and-replace?

我需要一个示例,说明如何通过 API 使用 Google 文档中的现有文本修改现有文档。 documentation 仅显示如何插入和删除文本,但未显示如何更新。一直在网上疯狂地寻找示例或指导,但没有成功。

终于自己想通了。

首先,按照this video准备Google Docs API的认证(虽然是Google Sheets但过程基本相同)。基本上它包括以下步骤:

  • Google Developer Console
  • 中创建项目
  • 启用 Google 文档 API
  • 创建凭据,包括用于编程访问的服务帐户
  • 与服务帐户客户电子邮件地址共享您的文档
  • 安装GoogleAPI的PHP客户端:composer require google/apiclient

然后创建如下脚本:

require_once(__DIR__ .'/vendor/autoload.php');
$client = new \Google_Client();
$client->setApplicationName('Some name');  //this name doesn't matter
$client->setScopes([\Google_Service_Docs::DOCUMENTS]);
$client->setAccessType('offline');
$client->setAuthConfig(__DIR__ .'/googleapi-credentials.json');  //see https://www.youtube.com/watch?v=iTZyuszEkxI for how to create this file
$service = new \Google_Service_Docs($client);

$documentId = 'YOUR-DOCUMENT-ID-GOES-HERE';  //set your document ID here, eg. "j4i1m57GDYthXKqlGce9WKs4tpiFvzl1FXKmNRsTAAlH"
$doc = $service->documents->get($documentId);

// Collect all pieces of text (see https://developers.google.com/docs/api/concepts/structure to understand the structure)
$allText = [];
foreach ($doc->body->content as $structuralElement) {
    if ($structuralElement->paragraph) {
        foreach ($structuralElement->paragraph->elements as $paragraphElement) {
            if ($paragraphElement->textRun) {
                $allText[] = $paragraphElement->textRun->content;
            }
        }
    }
}

// Go through and create search/replace requests
$requests = $textsAlreadyDone = $forEasyCompare = [];
foreach ($allText as $currText) {
    if (in_array($currText, $textsAlreadyDone, true)) {
        // If two identical pieces of text are found only search-and-replace it once - no reason to do it multiple times
        continue;
    }

    if (preg_match_all("/(.*?)(dogs)(.*?)/", $currText, $matches, PREG_SET_ORDER)) {
        //NOTE: for simple static text searching you could of course just use strpos()
        // - and then loop on $matches wouldn't be necessary, and str_replace() would be simplified
        $modifiedText = $currText;
        foreach ($matches as $match) {
            $modifiedText = str_replace($match[0], $match[1] .'cats'. $match[3], $modifiedText);
        }

        $forEasyCompare[] = ['old' => $currText, 'new' => $modifiedText];

        $replaceAllTextRequest = [
            'replaceAllText' => [
                'replaceText' => $modifiedText,
                'containsText' => [
                    'text' => $currText,
                    'matchCase' => true,
                ],
            ],
        ];

        $requests[] = new \Google_Service_Docs_Request($replaceAllTextRequest);
    }
    $textsAlreadyDone[] = $currText;
}

// you could dump out $forEasyCompare to see the changes that would be made

$batchUpdateRequest = new \Google_Service_Docs_BatchUpdateDocumentRequest(['requests' => $requests]);
$response = $service->documents->batchUpdate($documentId, $batchUpdateRequest);

这是我的方式 - 简单

public function replaceText($search, $replace)
{
    $client = $this->getClient();
    $service = new \Google_Service_Docs($client);
    $documentId = ''; // Put your document ID here


    $e = new \Google_Service_Docs_SubstringMatchCriteria();
    $e->text = "{{".$search."}}";
    $e->setMatchCase(false);


    $requests[] = new \Google_Service_Docs_Request(array(
        'replaceAllText' => array(
            'replaceText' => $replace,
            'containsText' => $e
        ),
    ));

    $batchUpdateRequest = new \Google_Service_Docs_BatchUpdateDocumentRequest(array(
        'requests' => $requests
    ));

    $response = $service->documents->batchUpdate($documentId, $batchUpdateRequest);
}