1

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

第一行是原始文本(用逗号分隔的字符串),第二行是所需的文本样式。 在此处输入图像描述

这是工作表(法语参数)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);
}
4

1 回答 1

2

One problem here is that the author names are sometimes separated by a comma and sometimes separated by just a space. See Ten., Benth., Swart, and (Ten.) Kerguélen. However, in your comment, you said this does not happen often though and that you could just deal with this manually, so let's just assume for now that author names are never separated commas.

With the assumption, we can split the contents of each cell by , and deal with each plant name/author separately:

const plants = text.split(', ')

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

What we need is to find the indices where the "plant author" substring starts and ends.

Finding the end index of the plant author substring is easy; it's just the end of the entire plant string:

const end = plant.length

To find the start of the plant author substring, we can look for the indices of the spaces ' '. (You'll need to write your own getIndices() method for this.) If the plant contains subsp. or var., the start index is the 4th space; otherwise, it is the 2nd 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

Once we have the start/end indices, we can put them in an array offsets that we will use to find the startOffset and endOffset values for the setTextStyle() method.

So now we have:

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
  })
}

Next, we have to initiate the RichTextValueBuilder object and loop through the offsets array to determine what the startOffset and endOffset values should be for the setTextStyles() method by adding where start and end values we found earlier to index

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
}

Finally, build the RichTextValue object:

richText = richText.build()

…and tie it all together with the rest of your code:

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;
}

I skipped over many details of how the Apps Script APIs work for spreadsheets and rich text formatting. You'll need to set your own styles, but from your code, it seems like you already know how to do this. The tricky part of your question is figuring out how to identify the author substring, so that's what I focused on for my answer.

于 2021-03-27T22:02:50.617 回答