Je détecterais les erreurs lorsqu'une formule contient une colonne manquante. Dans l'exemple suivant, un tableau contient 2 colonnes. En ajoutant une nouvelle colonne qui utilise une colonne inexistante, le résultat est manquant (correctement) et une erreur bloque mon script que je ne parviens pas à détecter car l'instruction try ne fonctionne pas. Existe-t-il une solution de contournement pour cela ?
dt= New Table( "Test",
Add Rows( 1 ),
New Column( "A",
Numeric,
"Continuous",
Format( "Best", 12 ),
Set Values( [2] )
),
New Column( "B",
Numeric,
"Continuous",
Format( "Best", 12 ),
Set Selected,
Set Values( [1] )
)
);
formula=":Name(\!"C\!") - :Name(\!"B\!")";
try(
eval(parse("dt << new column(\!"value\!", Numeric, \!"Continuous\!", Formula(" ||formula || "))"));
,
error="missing column";
);
@antonio-domenic , je crois que ce que vous voulez, c'est déterminer, avant d'essayer de créer une colonne basée sur une formule, si le tableau contient les colonnes appropriées pour la formule donnée ?Si vous êtes en mesure de déterminer cela avant d'essayer de créer la colonne, vous aurez moins de chances de rencontrer des erreurs d'arrêt de script.
La bonne nouvelle est qu'il est assez simple de déterminer tous les noms externes sur lesquels repose une formule - qui ne devraient être que des noms de colonne de la table de données actuelle.(Il est préférable de ne pas faire reposer une formule sur une variable actuellement dans la portée qui perdra sa portée à un moment donné dans le futur, provoquant une erreur de la formule).
Voici un exemple de code avec une fonction qui analyse de manière récursive les expressions (les formules ne sont bien sûr que des expressions) pour tous les noms pendants.Vous pouvez ensuite vérifier les noms de colonne de la table et appliquer si les noms de colonne satisfont la formule :
Names Default to Here( 1 );
dt= New Table( "Test",
Add Rows( 1 ),
New Column( "A",
Numeric,
"Continuous",
Format( "Best", 12 ),
Set Values( [2] )
),
New Column( "B",
Numeric,
"Continuous",
Format( "Best", 12 ),
Set Selected,
Set Values( [1] )
)
);
//recursively find all unassigned names within the formula -- we can test these against the column names
get dangling names = Function( {formula},
{Default Local},
parse formula = Function( {expr, names = {}, assigns = {}},
{Default Local},
If( Contains( Head Name( expr ), "[" ) & Contains( Head Name( expr ), "]" ), // deal with the exceptional case where JMP doesn't arg-parse out this pattern...
items = Words( Head Name( expr ), "[" );
Summation( i = 1, N Items( items ),
Try(
item = Word( 1, items[i], "]" );
If( Is Missing( Num( item ) ),
{n, a} = Recurse( Parse( item ) );
Insert Into( names, n );
Insert Into( assigns, a );
)
);<BR /> 0
)
,
If( Head Name( expr ) == "Assign", // if a variable is assigned within the formula then we don't care to check it (the formula shouldn't be direclty affecting other columns, it bad practice!)
Insert Into( assigns, Char( Arg( expr, 1 ) ) )
,
Head Name( expr ) != Char( Name Expr( expr ) ), // Need to recursively parse here
Summation( i = 1, N Arg( expr ),
{n, a} = Recurse( Arg( expr, i ) );
Insert Into( names, n );
Insert Into( assigns, a );
0
);
,
Insert Into( names, Char( Name Expr( expr ) ) ) // found a name
);
);
Eval List( {Associative Array( names ) << Get Keys, Associative Array( assigns ) << Get Keys} )
);
{names, assigns} = parse formula( Name Expr( formula ) );
names = Associative Array( names );
assigns = Associative Array( assigns );
names << Remove( assigns );
names = names << Get Keys;
names
);
formulas = {};
Insert Into( formulas, Expr( :Name("C") - :Name("B") ) );
local var = [1 => 3, 2 => 4];
Insert Into( formulas, Eval Expr(
var = Expr( local var );
var[:C][:F] + :D
);
);
Insert Into( formulas, Expr( :A + :B ) );
Insert Into( formulas, Expr( :A + :B - Sin( :D</img> + Cos( :E - :Name("flamingo@fish" ) ) ) ) );
For( i = 1, i <= N Items( formulas ), i++,
table columns = dt << Get Column Names( "String" );
Write( "\!N" );
Show( table columns );
formula references = get dangling names( formulas[i] );
refs = {};
For( j = 1, j <= N Items( formula references ), j++,
refs[j] = Contains( table columns, formula references[j] ) > 0
);
Show( formulas[i] );
Show( formula references );
Print( If( Sum( refs ) == N Items( formula references ), "OKAY", "NOT OKAY" ) );
If( Sum( refs ) == N Items( formula references ), // The table contains all the necessary columns, okay to add the new column!
Eval( Eval Expr(
dt << New Column( "FORMULA", <<FORMULA></FORMULA>Faites moi savoir si vous avez des questions!
Jordan,
Il serait peut-être préférable de tester avant de créer la colonne de formules. Faites donc une instruction if pour voir si la colonne existe ... si ce n'est pas le cas, ne créez pas la colonne de formule.
Merci, mais ce n'est pas si utile. Le problème est que j'extrait automatiquement certaines données (par script) et que certaines d'entre elles peuvent manquer (mais je ne sais pas à l'avance si et lesquelles). Le script s'arrête lorsque la colonne manquante est trouvée et c'est le vrai problème. Une bonne solution pourrait être l'instruction try, mais cela ne fonctionne pas.
Je ne sais pas exactement ce que vous voulez que le résultat final soit, si la colonne est manquante, mais ce qui suit est une façon de gérer le problème
dt = New Table( "Test",
Add Rows( 1 ),
New Column( "A",
Numeric,
"Continuous",
Format( "Best", 12 ),
Set Values( [2] )
),
New Column( "B",
Numeric,
"Continuous",
Format( "Best", 12 ),
Set Selected,
Set Values( [1] )
)
);
If( Try( dt:c << get name, "" ) == "",
type = "character";
formula = "\!"missing column\!"";
,
type = "numeric/continuous";
formula = ":Name(\!"C\!") - :Name(\!"B\!")";
);
Eval(
Parse(
"dt << new column(\!"value\!"," || type || ", Formula(" || formula
|| "))"
)
);