将文本样式应用于 google sheet 单元格中的正则表达式模式

Apply text syle to a regex pattern in google sheet cells

我想将部分字符串(通过正则表达式)转换为特定的文本样式,但我无法管理循环并且总是出错。请你帮助我好吗 ?非常感谢。

第一行是原文(字符串用逗号隔开),第二行是想要的文字样式。

这里是sheet(法语参数)https://docs.google.com/spreadsheets/d/1vq0Ai_wEr3MamEQ-kMsXW7ZGg3RxrrkE5lITcYjO-rU/edit?usp=sharing

function NomsStyleBotanique(){
  const classeur = SpreadsheetApp.getActive();  // var Feuille = classeur.getSheetByName('Feuille 1'); 
  var ligne = classeur.getCurrentCell().getRow();
  var colonne = classeur.getCurrentCell().getColumn();
  var range = classeur.getActiveRange();

  var richTextValues = range.getRichTextValues().map(([a]) => {
  var text = a.getText();
  var pos = 0;
  
  var myregEx = /,/g;
  var Noms = text.split(myregEx);
  
  var textStyleNomPlante = SpreadsheetApp.newTextStyle()
        .setFontSize(10)
        .setForegroundColor("black")
        .setFontFamily("Times New Roman")
        .setItalic(false)
        .build();

    var textStyleNomAuteur = SpreadsheetApp.newTextStyle()
        .setFontSize(10)
        .setForegroundColor("#616399")     // ("grey")
        .setFontFamily("Times New Roman")
        .setItalic(true)
        .build();

  var nbPhrases = [];
  var i =0;
 
  while (Noms){ i++; nbPhrases.push(Noms[i]); // SpreadsheetApp.getUi().alert(Noms[i]); 
  
  for (var i=0;i<nbPhrases.length;i++){
  
  var myarr = Noms[i].split(" ");
  var Espace1 = myarr[0].length+1;
  var Espace2 = myarr[1].length+1;

  if (Noms[i]){
    if ((Noms[i].indexOf("subsp") > 1) || (Noms[i].indexOf("var.") > 1)){
    var Espace3 = myarr[2].length+1;
    var Espace4 = myarr[3].length+1;
    pos = Espace1+Espace2+Espace3+Espace4; }

  else {   pos = Espace1+Espace2;  } // pos = text.match(new RegExp(/\s/, 'g'))[2]; 

  var position = pos;

  if (position > -1){
      var temp = a.getTextStyle(0, position - 1);

    return [
        SpreadsheetApp.newRichTextValue()
        .setText(Noms[i])
        .setTextStyle(0, position - 1, textStyleNomPlante)
        .setTextStyle(position, Noms[i].length, textStyleNomAuteur)
        .build()
      ];
    }
    return [SpreadsheetApp.newRichTextValue().setText(Noms[i]).setTextStyle(Noms[i].getTextStyle()).build()];
   }
  }
 }
} // fin boucle
);
range.setRichTextValues(richTextValues);
}

这里的一个问题是作者姓名有时用逗号分隔,有时只用 space 分隔。参见 Ten., Benth., Swart,(Ten.) Kerguélen。但是,在您的评论中,您说这种情况不会经常发生,您可以手动处理,所以我们现在假设作者姓名永远不会用逗号分隔。

有了假设,我们可以将每个单元格的内容按, 拆分,对每个植物name/author分别处理:

const plants = text.split(', ')

for (const plant of plants) {
  // Find start/end of authors substring.
}

我们需要找到“plant author”子字符串开始和结束的索引。

找到植物作者子字符串的结束索引很容易;它只是整个植物字符串的结尾:

const end = plant.length

要找到植物作者子串的开始,我们可以查找 spaces ' ' 的索引。 (您需要为此编写自己的 getIndices() 方法。)如果植物包含 subsp.var.,则起始索引是第 4 个 space;否则,它是第二个 space:

let start
spaceIndices = getIndices(plant, ' ')
if (plant.includes('subsp.') || plant.includes('var.')) start = spaceIndices[3] + 1  // Add 1 to not include the space itself
else start = spaceIndices[1] + 1  // Add 1 to not include the space itself

一旦我们有了 start/end 索引,我们就可以将它们放入一个数组 offsets 中,我们将使用该数组来查找 startOffsetendOffsetsetTextStyle()方法。

所以现在我们有:

const plants = text.split(', ')
let offsets = []
for (const plant of plants) {
  const end = plant.length
  
  let start
  spaceIndices = getIndices(plant, ' ')
  if (plant.includes('subsp.') || plant.includes('var.')) start = spaceIndices[3] + 1
  else start = spaceIndices[1] + 1

  offsets.push({
    start,
    end
  })
}

接下来,我们必须启动 RichTextValueBuilder 对象并循环遍历 offsets 数组以确定 startOffsetendOffset 值应该是什么 setTextStyles() 方法,方法是将我们之前找到的 startend 值添加到索引

let richText = SpreadsheetApp.newRichTextValue()
  .setText(text)
let authorTextStyle = SpreadsheetApp.newTextStyle()
  .setBold(true)
  .build()

let plantStartIndex = 0
for (const offset of offsets) {
  const startOffset = plantStartIndex + offset.start
  const endOffset = plantStartIndex + offset.end
  richText = richText.setTextStyle(startOffset, endOffset, authorTextStyle)
  plantStartIndex = plantStartIndex + offset.end + 2  // Add 2 to not include the ", " separator
}

最后,构建 RichTextValue 对象:

richText = richText.build()

...并将其与您的其余代码结合在一起:

function stylePlantNames() {

  const ss = SpreadsheetApp.getActive()
  const range = ss.getActiveRange()
  const values = range.getValues()

  let richTextValues = []

  for (const row of values) {
    let text = row[0]

    const plants = text.split(', ')

    let offsets = []
    for (const plant of plants) {
      const end = plant.length

      let start
      spaceIndices = getIndices(plant, ' ')
      if (plant.includes('subsp.') || plant.includes('var.')) start = spaceIndices[3] + 1
      else start = spaceIndices[1] + 1

      offsets.push({
        start,
        end
      })
    }

    let richText = SpreadsheetApp.newRichTextValue()
      .setText(text)
    let authorTextStyle = SpreadsheetApp.newTextStyle()
      .setBold(true)
      .build()

    let plantStartIndex = 0
    for (const offset of offsets) {
      const startOffset = plantStartIndex + offset.start
      const endOffset = plantStartIndex + offset.end
      richText = richText.setTextStyle(startOffset, endOffset, authorTextStyle)
      plantStartIndex = plantStartIndex + offset.end + 2
    }

    richText = richText.build()
    richTextValues.push([richText])

  }

  range.setRichTextValues(richTextValues)

}

function getIndices(str, char) {
  let indices = [];
  for (var i = 0; i < str.length; i++) {
    if (str[i] === char) indices.push(i);
  }
  return indices;
}

我跳过了有关 Apps 脚本 API 如何处理电子表格和富文本格式的许多细节。您需要设置自己的样式,但从您的代码来看,您似乎已经知道如何执行此操作。你的问题中棘手的部分是弄清楚如何识别作者子字符串,所以这就是我回答的重点。