【问题标题】:How to split 1 long paragraph to 2 shorter paragraphs? Google Document如何将 1 个长段拆分为 2 个短段?谷歌文档
【发布时间】:2020-03-04 07:19:55
【问题描述】:

我希望段落最多只有 3 个句子。

为此,我的策略是循环所有段落并找到第三句结尾(见注释)。然后,在其后添加一个“\r”字符。

这是我的代码:

for (var i = 1; i < paragraphs.length; i++) {
  ...
  sentEnds = paragraphs[i].getText().match(/[a-zA-Z0-9_\u0590-\u05fe][.?!](\s|$)|[.?!][.?!](\s|$)/g);
  //this array is used to count sentences in Hebrew/English/digits that end with 1 or more of either ".","?" or "!"
  ...
  if ((sentEnds != null) && (sentEnds.length > 3)) {
    lineBreakAnchor = paragraphs[i].getText().match(/.{10}[.?!](\s)/g);
    paragraphs[i].replaceText(lineBreakAnchor[2],lineBreakAnchor[2] + "\r");
  }
}

这适用于第 1 轮。但如果我再次运行代码 - 插入的“\r”字符后的文本不会被识别为新段落。因此,每次脚本运行时都会插入更多的“\r”(新行)。

如何让脚本“理解”“\r”表示新的、单独的段落?

还有其他角色/方法可以解决问题吗?

谢谢。

  • 注意:我使用句子的最后 10 个字符,假设匹配的唯一性足以进行 1 次替换。

【问题讨论】:

  • 试试\n,看看实际文档中是否有\n
  • 这不会改变所描述的行为
  • 您看到文档中是否有\n 吗?尝试使用正则表达式查找和替换菜单
  • 我做到了。 \n 在任何段落末尾都有一个匹配项。但是 - 即使我有脚本添加 \n - 在搜索中也没有检测到这些......
  • 尝试insertParagraphgetChildIdx 获取要插入的正确索引

标签: regex google-apps-script google-docs


【解决方案1】:

无需修改您自己的正则表达式即可实现此目的。

尝试这种方法来分割段落:

  • 获取文档的全部内容并创建句子数组。
  • 在原始段落之后插入不超过 3 个句子的段落。
  • 从地狱中删除原始段落。
function sentenceMe() {
  var doc = DocumentApp.getActiveDocument();
  var paragraphs = doc.getBody().getParagraphs();
  var sentences = [];
  // Split paragraphs into sentences
  for (var i = 0; i < paragraphs.length; i++) {
    var parText = paragraphs[i].getText();
    //Count sentences in Hebrew/English/digits that end with 1 or more of either ".","?" or "!"
    var sentEnds = parText.match(/[a-zA-Z0-9_\u0590-\u05fe][.?!](\s|$)|[.?!][.?!](\s|$)/g);
    if (sentEnds){
      for (var j=0; j< sentEnds.length; j++){
        var initIdx = 0;
        var sentence = parText.substring(initIdx,parText.indexOf(sentEnds[j])+3);
        var parInitIdx = initIdx;
        initIdx = parText.indexOf(sentEnds[j])+3;
        parText = parText.substring(initIdx - parInitIdx);
        sentences.push(sentence);
      }

    }
    // console.log(sentences);
  }

  inThrees(doc, paragraphs, sentences)
}

function inThrees(doc, paragraphs, sentences) {
  // define offset
  var offset = paragraphs.length;
  // Create paragraphs with up to 3 sentences
  var k=0;
  do {
    var parText = sentences.splice(0,3).join(' ');
    doc.getBody().insertParagraph(k + offset  , parText.concat('\n'));
    k++
  }
  while (sentences.length > 0)

    // Remove paragraphs from hell
    for (var i = 0; i < offset; i++){
      doc.getBody().removeChild(paragraphs[i]);
    }
}

如果您对自定义菜单有疑问,这里是:

function onOpen() {
  var ui = DocumentApp.getUi();
  ui.createMenu('Custom Menu')
  .addItem("3's the magic number", 'sentenceMe')
  .addToUi();
}

参考资料:

【讨论】:

    【解决方案2】:

    其实句子的检测并不是一件容易的事。

    • 句子并不总是以点、问号或感叹号结尾。如果句子以引号结尾,那么某些国家/地区的标点规则会强制您将句尾放在引号内:

      约翰问:“谁在那儿?”

    • 不是每个点都表示句子的结尾,通常大写字母后面的点不会结束句子,因为它出现在首字母之后。这里J.之后句子没有结束:

      最新的星球大战电影由 J.J. 执导。艾布拉姆斯。

    • 但是,有时句子确实以大写字母后跟一个点结束:

      该项目由 NASA 赞助。

    • 而且缩写会让人很难:

      有关更多信息,请查看 Phys 中的文章。 Rev. Letters 66, 2697, 2013。

    考虑到这些困难,让我们仍然尝试获得一些适用于“通常”情况的表达方式。

    进行全局匹配和替换。匹配

    ((?:[^.?!]+[.?!] +){3})
    

    并用

    替换它
    \1\r
    

    Demo

    这会查找 3 个句子(一个句子是一系列 not-dot、not-?、not-! 字符后跟一个点、一个 ? 或一个 ! 以及一些空格)并在它们之后放置一个 \r。

    2020 年 3 月 4 日更新

    试试这个:

    var regex = new RegExp('((?:[a-zA-Z0-9_\\u0590-\\u05fe\\s]+[.?!]+\\s+){3})', 'gi');
    for (var i = 1; i < paragraphs.length; i++) {
      paragraphs[i].replaceText(regex, '$1\\r');
    }
    

    【讨论】:

    • 谢谢亚历克斯。但是,不确定如何在代码中实现您的想法。我将分享更多我的代码来详细说明什么足以让我作为一个句子传递。
    • 更新了答案。我想段落包含一个文本字段列表,每个字段都包含多个段落。
    • 我得到这个:异常:无效的正则表达式模式 /((?:[a-zA-Z0-9_\u0590-\u05fe\s]+[.?!]+\s+){ 3})/giDetails
    • 另外,我不确定检测新行位置的替代方法是否解决了这里的实际问题(脚本添加了新行,但不将其视为段落分隔)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多