Ich würde Fehler abfangen, wenn eine Formel fehlende Spalten enthält. Im folgenden Beispiel enthält eine Tabelle 2 Spalten. Wenn ich eine neue Spalte hinzufüge, die eine nicht vorhandene Spalte verwendet, ist das Ergebnis ein fehlendes Ergebnis (korrekt) und ein Fehler, der mein Skript blockiert, das ich nicht abfangen kann, weil die Try-Anweisung nicht funktioniert. Gibt es dafür eine Problemumgehung?
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 , ich glaube, Sie möchten feststellen, ob die Tabelle die entsprechenden Spalten für die angegebene Formel enthält, bevor Sie versuchen, eine Spalte basierend auf einer Formel zu erstellen?Wenn Sie dies feststellen können, bevor Sie versuchen, die Spalte zu erstellen, ist die Wahrscheinlichkeit geringer, dass Sie auf Skriptstoppfehler stoßen.
Die gute Nachricht ist, dass es ziemlich einfach ist, alle externen Namen zu bestimmen, auf die sich eine Formel stützt – die nur Spaltennamen der aktuellen Datentabelle sein sollten.(Es hat sich bewährt, eine Formel nicht auf eine aktuell gültige Variable angewiesen zu lassen, die irgendwann in der Zukunft den Gültigkeitsbereich verliert, wodurch die Formel fehlerhaft wird).
Hier ist ein Beispielcode mit einer Funktion, die Ausdrücke (Formeln sind natürlich nur Ausdrücke) rekursiv auf alle baumelnden Namen analysiert.Sie können dann die Spaltennamen der Tabelle überprüfen und anwenden, wenn die Spaltennamen die Formel erfüllen:
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>Lassen Sie mich wissen, wenn Sie Fragen haben!
Jordanien,
Dies ist möglicherweise besser zu testen, bevor Sie die Formelspalte erstellen. Machen Sie also eine if-Anweisung, um zu sehen, ob die Spalte existiert. Wenn dies nicht der Fall ist, erstellen Sie die Formelspalte nicht.
Danke, aber es ist nicht so nützlich. Das Problem ist, dass ich einige Daten (per Skript) automatisch extrahiere und einige davon fehlen können (aber ich weiß nicht im Voraus, ob und welche). Das Skript stoppt, wenn eine fehlende Spalte gefunden wird, und das ist das eigentliche Problem. Eine gute Lösung könnte die try-Anweisung sein, aber sie funktioniert nicht.
Ich bin mir nicht ganz sicher, was das Endergebnis sein soll, wenn die Spalte fehlt, aber das Folgende ist eine Möglichkeit, das Problem zu lösen
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
|| "))"
)
);