J'ai actuellement un fichier séparé dans ce format (onglet "\t" de 3 colonnes séparés), et ";" sépare tous les éléments dans les colonnes).

    COL1\tCOL2\tCOL3
    abc\t123;1q\tapple\t
    dfg\t234;2w\tapple;apple\t
    hij\t345;3e\tbanana;apple;cherry;\t
    klm\t456;4r\tapple;banana;cherry;banana;cherry;\t
    nop\t567;5t\t;;apple;banana;cherry;banana;;cherry;;\t

J'aimerais avoir des idées sur une macro optimisée (idéalement javascript) pour manipuler le fichier pour SORTIR ceci : la colonne 3 est maintenant triée (tous les délimiteurs supplémentaires/non requis sont également supprimés) et les doublons sont supprimés. La nouvelle colonne 4 est le nombre d'éléments dédupliqués.

    abc\t123;1q\tapple\t1
    dfg\t234;2w\tapple\t1
    hij\t345;3e\tapple;banana;cherry\t3
    klm\t456;4r\tapple;banana;cherry\t3
    nop\t567;5t\tapple;banana;cherry\t3

J'ai essayé une méthode similaire à celle ci-dessous, mais cette méthode pourrait être plus rapide, je pense.

    for( iRow = 2; iRow <= totalLines; iRow++ ) { //traverse eash row, start at 2nd row
      str = document.GetCell(iRow, 2, eeCellIncludeQuotes);
      var count = (str.match(/;/g) || []).length;
      var numOfElements = count + 1;
      document.SetCell( iRow, 3, numOfElements, eeAutoQuote );
    }

Ainsi, l'utilisateur doit sélectionner la colonne sur laquelle il souhaite exécuter cela (colonne 3 dans cet exemple) et la macro s'exécutera uniquement sur cette colonne et affichera le nombre dans une nouvelle colonne à droite.

Les vrais fichiers source seront des millions de lignes, donc si cela pouvait être optimisé EmEditor de quelque manière que ce soit, ce serait formidable.

0
Venturer 15 sept. 2020 à 19:20

1 réponse

Meilleure réponse

J'ai optimisé votre macro en créant une fonction pour compter les points-virgules dans une chaîne plutôt que d'utiliser une expression régulière (deuxième version), et j'ai également utilisé les méthodes GetColumn et SetColumn pour augmenter la vitesse (troisième version). La troisième version insérera une colonne plutôt que d'écraser la colonne existante.

  1. Macro d'origine (modifiée pour l'exactitude et la synchronisation)

    var start = new Date().getTime();
    
    var totalLines = document.GetLines();
    for( iRow = 2; iRow <= totalLines; iRow++ ) { //traverse eash row, start at 2nd row
        str = document.GetCell(iRow, 3, eeCellIncludeQuotes);
        var count = (str.match(/;/g) || []).length;
        var numOfElements = count + 1;
        document.SetCell( iRow, 4, numOfElements, eeAutoQuote );
    }
    
    var end = new Date().getTime();
    var time = end - start;
    alert( "Execution time: " + time + " ms" );
    
  2. Deuxième version

    function CountSemiColon( str )
    {
        var count = 0;
        for( var index = -1; ; ) {
            index = str.indexOf( ';', index + 1 );
            if( index == -1 ) {
                break;
            }
            ++count;
        }
        return count;
    }
    
    var start = new Date().getTime();
    
    var totalLines = document.GetLines();
    for( iRow = 2; iRow <= totalLines; iRow++ ) { //traverse eash row, start at 2nd row
        var str = document.GetCell(iRow, 3, eeCellIncludeQuotes);
        document.SetCell( iRow, 4, CountSemiColon( str ) + 1, eeAutoQuote );
    }
    
    var end = new Date().getTime();
    var time = end - start;
    alert( "Execution time: " + time + " ms" );
    
  3. Troisième version

    function CountSemiColon( str )
    {
        var count = 0;
        for( var index = -1; ; ) {
            index = str.indexOf( ';', index + 1 );
            if( index == -1 ) {
                break;
            }
            ++count;
        }
        return count;
    }
    
    var start = new Date().getTime();
    
    var totalLines = document.GetLines();
    s1 = document.GetColumn( 3, "\n", eeCellIncludeQuotesAndDelimiter, 2, totalLines - 1 );
    sLines = s1.split( "\n" );
    s2 = "";
    nTotal = sLines.length;
    for( y = 0; y < nTotal; y++ ) {
        s2 += CountSemiColon( sLines[y] ) + 1 + "\n";
    }
    x = s2.length;
    if( x > 0 ) s2 = s2.substr( 0, x - 1 );
    document.InsertColumn( 4, s2, "\n", eeDontQuote, 2 );
    
    var end = new Date().getTime();
    var time = end - start;
    alert( "Execution time: " + time + " ms" );
    
  4. Quatrième version (renvoie 0 pour cellule vide)

    function CountElements( str )
    {
        if( str.length == 0 || str == '\t' ) {   // if empty string or delimiter only, return 0
            return 0;
        }
        var count = 0;
        for( var index = -1; ; ) {
            index = str.indexOf( ';', index + 1 );
            if( index == -1 ) {
                break;
            }
            ++count;
        }
        return count + 1;   // add 1 to the Count
    }
    
    var start = new Date().getTime();
    
    var totalLines = document.GetLines();
    s1 = document.GetColumn( 3, "\n", eeCellIncludeQuotesAndDelimiter, 2, totalLines - 1 );
    sLines = s1.split( "\n" );
    s2 = "";
    nTotal = sLines.length;
    for( y = 0; y < nTotal; y++ ) {
        s2 += CountElements( sLines[y] ) + "\n";
    }
    x = s2.length;
    if( x > 0 ) s2 = s2.substr( 0, x - 1 );
    document.InsertColumn( 4, s2, "\n", eeDontQuote, 2 );
    
    var end = new Date().getTime();
    var time = end - start;
    alert( "Execution time: " + time + " ms" );
    

Résultats des tests:

  1. 10429 ms
  2. 8496 ms
  3. 1803 millisecondes
  4. 1890 millisecondes

1 million de lignes, fichier CSV de 52 Mo.

Si ce n'est pas assez rapide, ou si une erreur "Out of Memory" se produit, je vais réfléchir à d'autres méthodes ou optimiser encore plus, alors faites-le moi savoir.

1
Yutaka 16 sept. 2020 à 17:34