使用 findText() 从 URL 获取路径元素

Get path element from URL using findText()

假设您在 Google 文档中有以下段落,并且您想从与汽车相关的 url 中提取该元素。

一些包含一些数据的段落有一个 url http://example.com/ford/some/other/data.html. There is also another link: http://example.com/ford/latest.html

我正在寻找的是从本段中提取 "ford" 以便我可以使用它。为了简单起见,我知道段落编号,下面我将其称为“1”。

我试过:

function getData() {
  var paragraphs = DocumentApp.getActiveDocument().getBody().getParagraphs();
  var element = paragraphs[1];
  var re = element.findText('http://example.com/([a-z])+/');
  var data = re.getElement().asText().getText();
  Logger.log(data);
}

问题是 data 包含整个段落文本。

还有没有一种方法可以捕获和使用来自捕获组的数据,也就是 () 中的内容?

我相信你的目标如下。

  • 您想使用 Google Apps 脚本从 http://example.com/ford/latest.htmlhttp://example.com/ford/some/other/data.html 等值中检索 ford 的值。
  • 这些值放在 Google 文档中。

为此,这个修改怎么样?

修改点:

在您的脚本中,当 element.findText('http://example.com/([a-z])+/') 具有值时,re.getElement().asText().getText() 是该段落的文本。在这种情况下,发现 element.findText() 的模式的文本包含在 element 中。使用这个,如何从 re.getElement().asText().getText()?

中检索像 ford 这样的值?

修改后的脚本:

从:
var data = re.getElement().asText().getText();
Logger.log(data);
到:
if (re) {
  var data = [...re.getElement().asText().getText().matchAll(/http:\/\/example\.com\/([\w\S]+?)\//g)];
  console.log(data.map(([,e]) => e));
} else {
  throw "Not match."
}
  • 当段落没有匹配您的正则表达式的值时,renull。请注意。

注:

  • 请使用启用 V8 的脚本。

参考:

作为 Tanaike 的补充,此答案旨在展示如果您必须使用 findText() 方法(例如同时更改元素属性、突出显示匹配范围等)可以做什么。


问题是"data"现在是整段

嗯,这完全是由于提供的说明:

  1. getElement() 的结果是 Element 本身。
  2. asText()Element 上的结果是 Text 实例。
  3. getText()Text 上的结果是,引用文档:

the contents of the element as text string


有没有办法捕获和使用数据

使用 findText() 在撰写本文时,根据 docs 似乎不可能,为后代引用它:

A subset of the JavaScript regular expression features are not fully supported, such as capture groups and mode modifiers.


怎么办?

找到匹配后,findText() return 是一个 RangeElement 实例,它有两个感兴趣的方法:getStartOffset()getEndOffsetInclusive()。这些方法的 return 值指向元素文本内容的字符 indices。因此,可以通过 substring() 方法(或通过 slice())提取匹配的子字符串。

可以使用findText()方法的from参数递归迭代匹配结果得到所有匹配范围

/**
 * @summary pattern wrapper
 * @param {string} linkPattern
 * @param {RegExp} [infoPattern]
 */
const matchText = (linkPattern, infoPattern) => 

  /**
   * @summary finds links in text elements
   * @param {GoogleAppsScript.Document.Paragraph} elem
   * @param {string} [text]
   * @param {GoogleAppsScript.Document.RangeElement} [from]
   * @param {string[]} [matches]
   * @returns {string[][]}
   */ 
  (elem, text = elem.getText(), from, matches = []) => {

    const match = from ? 
      elem.findText(linkPattern, from) : 
      elem.findText(linkPattern);

    if(match) {
       const rangeStart = match.getStartOffset();
       const rangeEnd = match.getEndOffsetInclusive();

       const link = text.substring( rangeStart, rangeEnd + 1 );
       const [ full, ...groups ] = link.match( infoPattern );

       matches.push(groups);

       return matchText(linkPattern, infoPattern)(elem, text, match, matches);
    }

    return matches;
  }

用于测试的驱动程序脚本:

function findText() {
  const doc = getTestDoc(); //gets doc somehow, not provided here

  const body = doc.getBody();

  const par = body.appendParagraph("Some paragraph with some data in it https://example.com/ford/some/other/data.html.\nThere is another link also here https://example.com/ford/latest.html.");

  const pattern = 'http(?:s)*:\/\/(?:www\.)*example\.com\/\w+';
  const targetPattern = /\/(\w+)$/;

  const results = matchText(pattern,targetPattern)(par);

  Logger.log(results); //[[ford], [ford]]
}

注释

  1. 奇怪的观察:显然,要将标记(\w\s 等)传递给表达式 string,必须 转义 反斜杠(例如 \w 将被正确解析)。
  2. 注意上面的解决方案return是一个string[][]来提取所有捕获组()
  3. 上面的示例代码专为 V8 运行时设计。

参考文献

  1. getElement() spec
  2. asText() spec
  3. getText() spec
  4. findText() spec
  5. getStartOffset() spec
  6. getEndOffsetInclusive() spec
  7. substring() docs 在 MDN