Google script : Masquer les colonnes contenant certains mots

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Voilà, j’essaye de construire un script qui m’affichera uniquement les lignes comportant un mot particulier. J’ai bien réussi à faire en sorte que la colonne soit cachés sur le premier mot qu’il trouve. Sauf que je n’arrive pas à faire la même chose sur tout les mots. J’ai essayé de boucler mais à chaque fois ça revient au début… Et avec findAll, j’ai un tableau qui sort, mais je n’arrive pas à l’exploiter pour sortir les index des mots. Du coup… Est-ce que quelqu’un aurait une idée de comment faire s’il vous plait ?

Merci d’avance.

function masquer(){
  var ss = SpreadsheetApp.getActiveSpreadsheet(); 
  var sheet = ss.getActiveSheet();
  
  var trouver = sheet.createTextFinder("Répertoire").findNext();
   Logger.log(trouver);
  var index = trouver.getColumn();
   Logger.log(index);
 
 sheet.hideColumns(index)
 }

le tout est de voir ce que retournera findNext s’il ne trouve rien.

D’après la documentation :

the next matching cell, or {code null} if there are no previous matches

ça signifie que tu dois pouvoir répéter ton traitement tant que ça ne retourne pas null.

const finder = sheet.createTextFinder("Répertoire")
let trouver =  finder.findNext()
while(trouver != null) {
    // on cache la colonne
    sheet.hideColumns(trouver.getColumn())
    // on va chercher la prochaine occurence
    trouver = finder.findNext()
}
+1 -0

Ooh oui je vois, merci ! Ca fonctionne en tout cas :D

Et je me demandais, est-ce qu’il n’y aurait pas plus simple ? hideColumns permet de cacher plusieurs colonnes à la fois, si on rentre le bon nombre d’index tandis que findAll renvoi un tableau de toutes les occurrences trouvé. C’était ma première piste de réflexion, je trouve ça plus logique de tout faire d’un coup plutôt que un par un avec une boucle.

Seulement, je n’arrive pas à extraire les index du tableau de findAll pour ensuite les donnes à hideColumns

quoi qu’il arrive il va falloir que tu boucles. La boucle sera soit dans le but de retrouver les index, soit de cacher les colonnes une par une.

le tableau que retourne findAll est un tableau de Range, il se manipule donc comme le Range dans la variable trouver.

const indices = []
for (const cell of sheet.createTextFinder("Répertoire").findAll()) {
   // pour chaque range du résultat, on met la colonne dans la table
   indices.push(cell.getColumn())
}
sheet.hideColumns(indices)

Notons que le gros avantage de la boucle while+findNext c’est qu’elle te permet de ne pas instancier deux tableaux en mémoire : à chaque fois le système obtient le prochain résultat et tu ne stockes rien de plus qu’une instance de Range.

J’ai une dernière question (désolé). Est-ce que TextFinder peut trouver les cellules qui ne contiennent pas le texte recherche ? (oui, j’ai pensé mon code à l’envers à la base >< je veux cacher les colonnes ne contenant pas le texte)

+0 -0

Je n’ai pas de certitude à ce propos, mais je tenterai bien une regexp :

const word = "Répertoire"
// regexp qui dit "commence par une chaîne qui ne contient pas  le mot répertoire"
const regexp = "^(?!.*${word})"
const finder = sheet.createTextFinder(regex).useRegularExpression(true)
// la suite du code

Attention, je n’ai pas pu tester que ça fonctionnait.

J’ai testé. Le code n’indique pas d’erreur (j’ai modifié le TextFinder pour rajouter le p à regex) mais il ne fait pas ce qu’on lui demande. Si j’en crois la mise en page de google script, il ne detecte pas la variable word dans la const regexp.

Alors, là il y a deux choses, en une:

  • l’interprétation de string
  • la regexp

En JS moderne, tu peux dire "je veux utiliser la valeur d’une variable à l’intérieur d’un string" en utilisant la syntaxe à base d’antiquotes et de ${}.

Par exemple :

let mascotte = "clem"
let site = "zds"
let avant = "zozor"
console.log(`la mascotte de ${site} est ${mascotte} alors que celle du ${site.split("").reverse().join("")} était ${avant}`)
// affiche "la mascotte de zds est clem alors que celle du sdz était zozor"

ensuite tu as la regexp.

Sache que pour la faire, celle-là j’ai dû regarder sur internet. Ceci dit le principe est le suivant : pour dire "ne contient pas le mot "x"" tu est obligé de dire "commence par une chaîne qui ne se termine pas par le mot x" (ça marche aussi avec finir d’ailleurs). Et c’est là que c’est compliqué à exprimer.

L’astuce c’est d’utiliser les "forward reference", c’est technique et compliqué. Mais globalement (?! signifie "on ne doit pas trouver ce qui va suivre jusqu’à la parenthèse fermante".

du coup je dis "on ne doit pas trouver n’importe quel caractère puis le mot que je cherche". ainsi on a bien le contrat "on commence par une chaîne qui ne se termine pas par le mot que je cherche".

Mmh oui, le JS moderne je le vois de plus en plus passer, j’avoue que c’est assez flou. J’ai "l’habitude" du JS classique, que je maitrise pas forcément donc les nouvelles écritures… c’est trèèès flou. Surtout si je dois l’appliquer aux trucs de google script qui a ses propres classes etc. Je tâtonne beaucoup.

Ok alors la regexp je vais la ranger dans un coin de mon cerveau et probablement l’oublier rapidement xD. Parce que "commencé par ce qui ne termine pas" c’est assez étrange comme phrase, mais je pense avec "saisi" vaguement le concept. C’est un peu la version évolué et boosté aux hormones des * que l’on met comme joker de recherche.

Merci pour l’explication en tout cas ! J’ai pas encore fini tout ce que je voulais faire de mon code mais avec un peu de chance et beaucoup de recherche, j’y arriverai peut être seul x)

+0 -0

Bon ben… je bloque de nouveau.

Le principe de findText étant de chercher dans toute la feuille (ou bien le classeur ou une cellue) je n’arrive pas à lui indiquer de ne chercher que dans une seule ligne. J’ai modifié le code pour qu’il commence à une cellule donné mais c’est tout ><

function recherche(){
  var ss = SpreadsheetApp.getActiveSpreadsheet(); 
  var sheet = ss.getActiveSheet();
 // var range = sheet.getRange("D2");
 // var ligne = range.getRow();

 //const finder = sheet.createTextFinder("Répertoire");
 //let trouver =  finder.findNext();

const word = "Répertoire";
// regexp qui dit "commence par une chaîne qui ne contient pas  le mot répertoire"
const regexp = `^(?!.*${word})`;
//const finder = ligne.createTextFinder(regexp).useRegularExpression(true);
const finder = sheet.createTextFinder(regexp).useRegularExpression(true);
let trouver =  finder.startFrom(ss.getRange("D2")).findNext();

while(trouver != null) {
    // on cache la colonne
    sheet.hideColumns(trouver.getColumn())
    // on va chercher la prochaine occurence
    trouver = finder.findNext()
  }
}

A priori, la fonction createTextFinder peut être appelée sur un Range.

Du coup il te suffit d’appeler :

const row = sheet.getRange("4:4") // sélectionne la ligne 4
const word = "Répertoire";
// regexp qui dit "commence par une chaîne qui ne contient pas  le mot répertoire"
const regexp = `^(?!.*${word})`;
//const finder = ligne.createTextFinder(regexp).useRegularExpression(true);
const finder = row.createTextFinder(regexp).useRegularExpression(true);
// reste du code

Ah oui, j’avais tenté un truc avec range (comme peut en témoigner mes lignes cachés) mais je ne savais pas qu’on pouvait sélectionner toute une ligne avec range ! Je pensais que c’était uniquement une cellule donc j’essayais pas un moyen détourné x)

Encore merci

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte