Date
1  9 of 9
[Clip] VanWeerthuizenian Expressions
Art Kocsis
At 9/10/2013 05:11 PM, Flo wrote:
It has been discussed several times that NT doesn't master Boolean Expressions (cf message #21773). And we considered tools like DOS Findstr, Agent Ransack etc to be used in this case. It should also be mentioned that, to some extent, we could simulate Boolean Expressions with RegEx.Flo, If I can jump in here. [Sorry for the length. This was meant to be a quicky but it grew!] In testing boolean expressions I prefer converting them to simple arithmetic expression rather than a series of IF  Than  Else trees. If you restrict the values of your logical variables to either zero or one you can take advantage of the common properties between arithmetic and logic systems and use arithmetic instead of if tests to evaluate logical expressions. Since zero is the identity element for addition and one is the identity element for multiplication and letting one equal true and zero equal false, one can map all logical operations and expressions onto equivalent arithmetic operations and expressions. Basic properties: ================= Identity Elements: 0, 1 (Add, Mult) <==> False, True (OR, AND) Operators: Negation, Mult, Add, MOD <==> NOT, AND, OR, XOR Precedence: Negation=>Mult=>Add <==> NOT=>AND=>OR Distributive: I AND (J OR K) == (I AND J) OR (I AND K) Commutative: (I • J) == (J • I) Associative: (I • J • K) == (I • J) • K == I • (J • K) Where • = either OR or AND; Optional parentheses added for clarity Logical Identities († De Morgan's Laws) ======================================== A OR False = A A AND TRUE = A NOT (A AND B) = (NOT A) OR (NOT B) † NOT (A OR B) = (NOT A) AND (NOT B) † (A XOR B) = (A AND NOT B) OR (NOT A AND B) Logical  Arithmetic Equivalents ================================ A OR FALSE <==> A + 0 = A A AND TRUE <==> A * 1 = A A OR B <==> MAX (A, B) A AND B <==> A * B NOT A <==> (A + 1) MOD 2 A XOR B <==> (A + B) MOD 2 NOT A AND B <==> (MIN (A, B) + 1) MOD 2 NOT A OR B <==> (MAX (A, B) + 1) MOD 2 NOT A XOR B <==> ((A + B) Mod 2 + 1) MOD 2 == (A + B + 1) Mod 2 [Hopefully Yahoo's reformatting doesn't bastardize those tables too much. See separate post and uploaded file for clips implementing each of the above seven nontrivial operations. These tables and more info is included in the uploaded cliplib.] Now, getting back to your original example, your simple conjunction: ^!If ^$Calc(MIN(^%A%;MIN(^%B;MIN(^%C%;MIN(^%D%;1^%E%)))))$=1 Next Else Skip reduces to just the product of the variables: ^!If ^$Calc(^%A%*^%B*^%C%*^%D%*^%E%)$=1 Next Else Skip The analogous test for unions would simply be the sum of the variables compared to zero. However, for more complex expressions that doesn't work since using a sum operation for unions can result in values not contained in the set {0,1}. However, by using the above identities it is possible to transform any expression into a pure product expression (or other form), which might or might not simplify your code. For example: (A AND B AND C) OR (B AND NOT D) is equivalent to NOT (A AND B AND C) AND NOT (B AND NOT D) Note also that since the operations are commutative, associative and distributive, B may be "factored" out to make an equivalent expression (from the original): B AND ((A AND C) OR (NOT D)) As you can see, you can play around with logical expressions just like we did with trig equations in HS to simplify (or to make them more complex). For specific applications you can write down and optimize the truth table (I forget what the name for the process is). This is done quite frequently for logic circuits as the optimization pays off in reduced components and gate delays. That may not be as beneficial for software. There is a formal process that guarantees an optimum result but is has been too many years to remember. Short of that just eye balling the truth table could reveal some useful reductions. For four input conditions it is only a 16 by 16 table. Or you could use the logic functions I will post later. All this is a perfect example for the need for Notetab to fully support custom functions. By fully support I mean supporting Far Functions and being usable in clipbar clips. Custom functions are very useful and handy tools. They can make the code easier to write and program flow much more transparent. They greatly reduce code size (at least by 50% where you can use them). Thanks to Ian Ntnerd's post last August there is a workaround for FarFunctions. However, custom functions still have one fatal dealbreaking (for me), drawback: They CANNOT be reliably used for any clipbar clips! •In Notetab, all variables are global but the clipbar uses a separate storage area •Variable values set in clipbook panel are not seen by clip bar clips & vice versa •Clipbar clip variables are not global across different clipbooks Perhaps if we make enough noise and we can get the no clipbar restriction removed. It would greatly enhance the clip functionality and ease coding efforts. Namaste', Art OK, this was bugging me so I had to look it up. Geesh. it's only been 40+ years. One shouldn't forget so soon!!! The process of optimizing a truth table is called a Karnaugh map http://en.wikipedia.org/wiki/Karnaugh_map The formal name for the Boolean identities above is De Morgan's laws http://en.wikipedia.org/wiki/De_Morgan%27s_laws Two other terms that you may want to look up are "Disjunctive Normal Form (DNF)" and its dual, the "Conjunctive Normal Form (CNF)". http://en.wikipedia.org/wiki/Disjunctive_normal_form http://en.wikipedia.org/wiki/Conjunctive_normal_form These are canonical forms for describing the truth table for a system. A DNF is a disjunction of conjunctive clauses, also known as an "OR of ANDs" or a "sum of products". A CNF is a conjunction of a disjunction of literals, also known as an "AND of ORs" or a "product of sums". Basically they are fully expanded forms that involve only one level of parentheses.


flo.gehrke <flo.gehrke@...>
 In ntbclips@..., Art Kocsis <artkns@...> wrote:
Thanks for your explanations, Art! This is certainly a great help for users trying to go further into that topic. However, I would like to get back to my question concerning the specific concept that was introduced by Wayne VanWeerthuizen (where is he?) with his abovementioned 'NoteTab Tutorial Control Structures v003.OTL'... Is anyone (also Wayne himself) still using such expressions andSo far, Wayne gave us the solution for only five conditions. Given a simple list... A B A B C A C D B D E F we could test Wayne's five expressions against that list with the following clip... ^!Set %Lines%=^$GetTextLineCount$ ^!Set %Row%=1 ^!Goto ^?{(H=5)Find lines matching...==A AND BA OR BA NOT BA XOR BNOT A} :A AND B :Loop_1 ^!Set %A%=0; %B%=0 ^!Jump ^%Row% ^!IfMatch "^.*A.*$" "^$GetLine$" ^!Set %A%=1 ^!IfMatch ".*B.*$" "^$GetLine$" ^!Set %B%=1 ^!If ^$Calc(MIN(^%A%;^%B%))$=1 Next Else Skip ^!Set %Hits%=^%Hits%^$GetLine$^P ^!Inc %Row% ^!If ^$GetRow$ < ^%Lines% Loop_1 ^!Info [L]Expression: A AND B^P^PMatches:^P^%Hits% ^!Goto Out :A OR B :Loop_2 ^!Set %A%=0; %B%=0 ^!Jump ^%Row% ^!IfMatch "^.*A.*$" "^$GetLine$" ^!Set %A%=1 ^!IfMatch ".*B.*$" "^$GetLine$" ^!Set %B%=1 ^!If ^$Calc(MAX(^%A%;^%B%))$=1 Next Else Skip ^!Set %Hits%=^%Hits%^$GetLine$^P ^!Inc %Row% ^!If ^$GetRow$ < ^%Lines% Loop_2 ^!Info [L]Expression: A OR B^P^PMatches:^P^%Hits% ^!Goto Out :A NOT B :Loop_3 ^!Set %A%=0; %B%=0 ^!Jump ^%Row% ^!IfMatch "^.*A.*$" "^$GetLine$" ^!Set %A%=1 ^!IfMatch ".*B.*$" "^$GetLine$" ^!Set %B%=1 ^!If ^$Calc(MIN(^%A%;1^%B%))$=1 Next Else Skip ^!Set %Hits%=^%Hits%^$GetLine$^P ^!Inc %Row% ^!If ^$GetRow$ < ^%Lines% Loop_3 ^!Info [L]Expression: A NOT B^P^PMatches:^P^%Hits% ^!Goto Out :A XOR B :Loop_4 ^!Set %A%=0; %B%=0 ^!Jump ^%Row% ^!IfMatch "^.*A.*$" "^$GetLine$" ^!Set %A%=1 ^!IfMatch ".*B.*$" "^$GetLine$" ^!Set %B%=1 ^!If ^$Calc(ABS(^%A%^%B%))$=1 Next Else Skip ^!Set %Hits%=^%Hits%^$GetLine$^P ^!Inc %Row% ^!If ^$GetRow$ < ^%Lines% Loop_4 ^!Info [L]Expression: A XOR B^P^PMatches:^P^%Hits% ^!Goto Out :NOT A :Loop_5 ^!Set %A%=0 ^!Jump ^%Row% ^!IfMatch "^.*A.*$" "^$GetLine$" ^!Set %A%=1 ^!If ^$Calc(1^%A%)$=1 Next Else Skip ^!Set %Hits%=^%Hits%^$GetLine$^P ^!Inc %Row% ^!If ^$GetRow$ < ^%Lines% Loop_5 ^!Info [L]Expression: NOT A^P^PMatches:^P^%Hits% ^!Goto Out :Out ^!ClearVariables As far as I can see, the clip gets to correct results. Nevertheless, for me the question remains: Is there any way to enlarge Wayne's concept to conditions like 'A AND B AND NOT (E OR D)', for example? Or is there no way to get beyond the borders of those five conditions? Regards, Flo P.S. Regarding... Too often help is solicited and answers posted with nary a wordHow right you are.... :(


Art Kocsis
Sorry, another long post. But there's a lot to
cover.
On Wed 11 Sep 2013 08:10:08 0700 Flo said: "...what matters here is this specific approach which  as Wayne explained  could apply to much more complex queries (with AND, OR, XOR, NOT etc). In cases like that, it would be difficult to use RegEx, and compound loops would end in extremely long "IF, ELSE IF, ELSE IF Chains" (Wayne)." On Thu, 19 Sep 2013 03:52:04 0000 Flo said: "Nevertheless, for me the question remains: Is there any way to enlarge Wayne's concept to conditions like 'A AND B AND NOT (E OR D)', for example? Or is there no way to get beyond the borders of those five conditions?" BTW Five??? I only see four: NOT, OR, AND, XOR. And those are operators, not conditions. What am I missing> ############################################# Flo, I think what you are asking is: given the absence of logical operators in Notetab Clip Code, how can I generalize the use of arithmetic operators to apply them to complex logical expressions without obtuse and lengthy If  Then  Else trees. The answer has two parts: 1: The mapping of the logical operations to arithmetical operations 2: The transformation of complex logical expressions into canonical form Regarding #1, there are a number of different mapping of logical to arithmetical operations as Wayne and I have discussed and with no major standouts among them. They all suffer from the inherent limitation of being strictly binary operations in Notetab, (i.e., MAX (A,B,C,D...) is not allowed). To recap two mappings: Operation Addition only Allowing Subtraction ============ ====================== ===================== NOT A <==> (A + 1) MOD 2 (1  A) A AND B <==> A * B MIN (A, B) A OR B <==> MAX (A, B) MAX (A, B) A XOR B <==> (A + B) MOD 2 ABS (AB) NOT A AND B <==> (MIN (A, B) + 1) MOD 2 1  MIN (A,B) NOT A OR B <==> (MAX (A, B) + 1) MOD 2 1  MAX (A,B) NOT A XOR B <==> (A + B + 1) MOD 2 1  ABS (AB) Regarding #2 as Joy and I discussed, any logical expression can be transformed into an equivalent DNF (an OR of ANDs), or CNF (an AND of ORs), expression. These canonical expressions use only the three logical operators: NOT, AND and OR. You can do that transform either by a series of transformations using DeMorgan's laws or  easier for very complicated expressions  by using truth tables. Each row in a truth table is a conjunction (AND) of the state of the columns (conditions). The disjunction (OR) of all the rows resulting in a true (=1) state is the DNF (Disjunctive Normal Form) of the system. For example: ## A B C D E X Y1 Y2 Y3 Y DNF Term == = = = = = = == == == = ====================== 01 0 0 x 0 0 0 0 0 0 0 02 0 0 x 0 1 0 0 0 0 0 03 0 0 x 1 0 0 0 0 1 1 ¬A AND ¬B AND D AND ¬E 04 0 0 x 1 1 0 0 0 0 0 05 0 1 x 0 0 0 0 0 1 1 ¬A AND B AND ¬D AND ¬E 06 0 1 x 0 1 0 0 1 0 1 ¬A AND B AND ¬D AND E 07 0 1 x 1 0 0 0 1 1 1 ¬A AND B AND D AND ¬E 08 0 1 x 1 1 0 0 0 0 0 09 1 0 x 0 0 0 0 0 0 0 10 1 0 x 0 1 0 0 0 0 0 11 1 0 x 1 0 0 0 0 0 0 12 1 0 x 1 1 0 0 0 0 0 13 1 1 x 0 0 1 1 0 0 1 A AND B AND ¬D AND ¬E 14 1 1 x 0 1 0 0 0 0 0 15 1 1 x 1 0 0 0 0 0 0 16 1 1 x 1 1 0 0 0 0 0 For instance, taking your example, A AND B AND NOT (E OR D), (Col X), the DNF form for X is simply row 13: X = A AND B AND ¬D AND ¬E (where ¬ is the NOT operator). That seems like a lot of work compared to the trivial DeMorgan transformation but this is meant to illustrate a process so let's add some complication: Let Y = [A AND B AND NOT (E OR D)] OR {¬A AND [B AND (¬D OR E) OR B AND (D OR ¬E)]} OR [(¬A AND ¬E AND (B OR D)] = Y1 OR Y2 OR Y3 Where Y1 = A AND B AND NOT (E OR D) Y2 = ¬A AND [B AND (¬D OR E) OR B AND (D OR ¬E)] Y3 = (¬A AND ¬E AND (B OR D) The Y column is the conjunction of the Y1, Y2 and Y3 columns and the final DNF expression is just the OR (Sum), of the Y rows with true values: Y = R3 OR R5 OR R6 OR R7 OR R13 = (¬A AND ¬B AND D AND ¬E) OR (¬A AND B AND ¬D AND ¬E) OR (¬A AND B AND ¬D AND E) OR (¬A AND B AND D AND ¬E) OR (A AND B AND ¬D AND ¬E) This logical expression can now be evaluated in six clear and easily followed steps, none of which involve an If test: Evaluate each of the five row expressions using the canonical AND operations Evaluate the final result using the canonical OR operation on those five results. Alternatively, the expression could be coded directly using my functions. I did find it necessary to first transform the expression from embedded binary notation to prefix notation. Even then I had to be very careful not to introduce an error. I could then use NTB's replace dialog to convert to Clip syntax. Without a parser to analyze and convert an arbitrary expression with nested parentheses to Notetab format it still is a bit tricky. The functions work well for short or medium complexity expressions but a truth table is easier and more reliable for anything more complex. Y1 = and(A,B,¬or(E,D)) Y2 = and(¬A,¬E,or(B,D)) Y3 = and(¬A,or(and(B,or(¬D,E)),and(B,or(D,¬E)))) ^!Set %Y1%^$AND(^%A%,^%B%,^$NOR(^%E%,^%D%)$)$ ^!Set %Y2%^$AND(^$NOT(^%A%)$$,^$NOT(^%E%)$$,^$OR(^%B%,^%D%)$)$ ^!Set %Y3%^$AND(^$NOT(^%A%)$$,^$OR(^$AND(^%B%,^$OR(^$NOT(^%D%)$$,^%E%)$)$,^$AND(^%B%,^$OR(^%D%,^$NOT(^%E%)$$)$)$ ^!Set %Y%=^$OR(^%Y1%;^%Y2%;^%Y3%)$ Some things to notice/consider: • The astute reader will notice that Y2 is equivalent to ¬A AND B AND (D XOR E) However, remember we are limiting ourselves to NOT, AND and OR operators. • Separating the terms into partial result columns makes it easier and less error prone to generate the truth table. • There can be some overlap in the partial results (e.g., row 7, col Y2 and Y3) • The growth of terms (and complexity) is linear, not exponential • Changes to the system criteria (truth table), are easily and fairly reliably propagated to the DNF expression terms (this is much, much less error prone than If  Then  Else logic trees. • Additional columns can easily be added to record the results of alternate logical expressions using the same worksheet and input parameters states. • The truth table is independent and external to any program language or code. It is simply prep work prior to program implementation. • A truth table is easy to generate, easy to understand and concise in execution • Most important, using a truth table to analyze and code logic expressions is the most reliable and least error prone method available. OTOH, Trying to implement complex expressions by means of If  Then  Else trees is a recipe for frustration and errors. Clear computation and program flow is a basic requirement for generating error free code as well for downstream maintainability. The VanWeerthuizenian Expressions get very messy very, very quickly once you go beyond the trivial two parameter, binary condition unless you restrict yourself to canonical forms. This is primarily due to the restriction of the MAX and MIN functions to two operands. That is why I removed that restriction from my AND and OR functions. However, in canonical form the benefit of my functions is much less dramatic than I expected. For example for R3 = ¬A AND ¬B AND D AND ¬E ^!Set %R3%=^$Calc(min((1^%A%),min((1^%B%),min(^%D%,(1^%E%))));0)$ vs ^!Set %R3%=^$AND(^$NOT(^%A%)$;^$NOT(^%B%)$;^%D%;^$NOT(^%E%)$)$ I think the functions are clearer and less error prone than all the nested parentheses and remembering the correct mappings but not earth shakingly so. However, the major point and lesson here is the transformation to DNF form. Whether you use the VanWeerthuizenian constructs or my functions, the best path to error free coding and ease of maintenance is to transform your test criteria into canonical form using a single variable for each criteria, generate the DNF expression (by either Boolean transformations or via a truth table), and then evaluate the resulting products and sums. Do not use an If test until the final result. Applying this paradigm to your example: {A AND BA OR BA NOT BA XOR BNOT A} Let Y1 = A AND B; Y2 = A OR B; Y3 = A NOT B; Y4 = A XOR B; Y5 = NOT A The truth table is: # A B Y1 Y2 Y3 Y4 Y5 = = = == == == == == 1 0 0 0 0 0 0 1 2 0 1 0 1 0 1 1 3 1 0 0 1 1 1 0 4 1 1 1 1 0 0 0 And the DNFs for the five cases are: Y1 = A AND B Y2 = A OR B Y3 = A AND ¬B Y4 = ¬A AND B OR A AND ¬B Y5 = ¬A It doesn't seem like we gained much but yours is a fairly trivial test and remember, I am illustrating a generalized process, not content. Implementing this in a clip: ;######################### Start of Clip Code ############################### ;^!SetDebug On ^!Set %Lines%=^$GetTextLineCount$ ^!Set %Row%=1; %Hits%=^%Empty% ^!Set %Case%=^?{(H=5)Find lines matching...==_A AND BA OR BA NOT BA XOR BNOT A} :Loop ^!Jump ^%Row% ^!Set %A%=0; %B%=0; %Y%=0 ^!IfMatch "^.*A.*$" "^$GetLine$" ^!Set %A%=1 ^!IfMatch ".*B.*$" "^$GetLine$" ^!Set %B%=1 ^!Set %Y1%=^$Calc(MIN(^%A%;^%B%))$ ^!Set %Y2%=^$Calc(MAX(^%A%;^%B%))$ ^!Set %Y3%=^$Calc(MIN(^%A%;1^%B%))$ ^!Set %Y41%=^$Calc(MIN(1^%A%;^%B%))$ ^!Set %Y42%=^$Calc(MIN(^%A%;1^%B%))$ ^!Set %Y4%=^$Calc(MAX(^%Y41%;^%Y42%))$ ^!Set %Y5%=^$Calc(1^%A%)$ ^!IfMatch "^%Case%" "A AND B" ^!Set %Y%=^%Y1% ^!IfMatch "^%Case%" "A OR B" ^!Set %Y%=^%Y2% ^!IfMatch "^%Case%" "A NOT B" ^!Set %Y%=^%Y3% ^!IfMatch "^%Case%" "A XOR B" ^!Set %Y%=^%Y4% ^!IfMatch "^%Case%" "NOT A" ^!Set %Y%=^%Y5% ^!IfTrue ^%Y% ^!Set %Hits%=^%Hits%^$GetLine$^P ^!Inc %Row% ^!If ^$GetRow$ < ^%Lines% Loop ^!Info [L]Expression: ^%Case%^P^PMatches:^P^%Hits% ^!GoTo End ;Alternate set of logic expression calculations ^!Set %Y1%=^$AND(^%A%;^%B%)$ ^!Set %Y2%=^$OR(%A%;^%B%)$ ^!Set %Y3%=^$AND(^%A%;^$NOT(^%B%)$)$ ^!Set %Y41%=^$AND(^$NOT(^%A%);^%B%)$;)$ ^!Set %Y42%=^$AND(^%A%;^$NOT(^%B%)$)$ ^!Set %Y4%=^$OR(^%Y41%;^%Y42%)$ ^!Set %Y5%=^$NOT(^%A%)$ ;######################### End of Clip Code ############################### This, of course, could be rearranged to use your computed GoTos, the DNF computations could be moved to the %case% tests with only %Y41% and %Y42% precomputed or other optimizations which might or might not be significant depending on the application but would probably be at the cost of clarity and generalization. Remember, the emphasis here is on clarity of program flow (primarily linear), to minimize coding errors and to ease maintenance. The various sections are segregated, similar operations are consolidated, and program branches are minimized. A flow chart of this clip would not have any crossed lines. I hope this answers your questions. Art


Wayne VanWeerthuizen
Is VanWeerthuizenian really a word? Wow.
What is the current state of your research on VanWeerthuizenian Expressions? I've been out of the loop regarding NoteTab stuff for several years.


Michael Gerholdt
"Wayne's Project Manager" has been a staple for me for many years.
Best Regards, Michael Gerholdt ________________________________ From: Clips@Notetab.groups.io <Clips@Notetab.groups.io> on behalf of Wayne VanWeerthuizen <waynemv@...> Sent: Friday, September 18, 2020 3:48:33 AM To: Clips@Notetab.groups.io <Clips@Notetab.groups.io> Subject: Re: [NTBClps] [Clip] VanWeerthuizenian Expressions Is VanWeerthuizenian really a word? Wow. What is the current state of your research on VanWeerthuizenian Expressions? I've been out of the loop regarding NoteTab stuff for several years.


Wayne VanWeerthuizen
Have you had to make any modifications to Project Manager over the years?
Can I get a copy of the version you're using to compare with what I have?


Michael Gerholdt
I have not changed it.
Certainly. Best Regards, Michael Gerholdt ________________________________ From: Clips@Notetab.groups.io <Clips@Notetab.groups.io> on behalf of Wayne VanWeerthuizen <waynemv@...> Sent: Friday, September 18, 2020 8:36:31 PM To: Clips@Notetab.groups.io <Clips@Notetab.groups.io> Subject: Re: [NTBClps] [Clip] VanWeerthuizenian Expressions Have you had to make any modifications to Project Manager over the years? Can I get a copy of the version you're using to compare with what I have?


Michael Gerholdt
Wayne email pmgerholdt@...
Best Regards, Michael Gerholdt ________________________________ From: Clips@Notetab.groups.io <Clips@Notetab.groups.io> on behalf of Michael Gerholdt <pmgerholdt@...> Sent: Friday, September 18, 2020 8:49:24 PM To: Clips@Notetab.groups.io <Clips@Notetab.groups.io> Subject: Re: [NTBClps] [Clip] VanWeerthuizenian Expressions I have not changed it. Certainly. Best Regards, Michael Gerholdt ________________________________ From: Clips@Notetab.groups.io <Clips@Notetab.groups.io> on behalf of Wayne VanWeerthuizen <waynemv@...> Sent: Friday, September 18, 2020 8:36:31 PM To: Clips@Notetab.groups.io <Clips@Notetab.groups.io> Subject: Re: [NTBClps] [Clip] VanWeerthuizenian Expressions Have you had to make any modifications to Project Manager over the years? Can I get a copy of the version you're using to compare with what I have?


flo.gehrke@...
Wayne wrote...
Is VanWeerthuizenian really a word? Wow.I have taken the liberty of introducing this term with my message #23917 of 9/11/13. It refers to the "Performing Boolean Calculations" part in your tutorial. I hope you won't hold that against me ;) If anyone wants to test the example in my message again he must note that GROUPS.IO spoiled the clipcode. For example, '\b' was replaced with '\b'. Obviously, this happened with the transfer from Yahoo to GROUPS.IO. Here is a correction: ^!Set %Lines%=^$GetTextLineCount$ ^!Set %Row%=1 :Loop ^!Set %A%=0; %B%=0; %C%=0; %D%=0; %E%=0 ^!Jump ^%Row% ; Condition #1: a string of 8 characters ^!If ^$StrPos("\b.{8}\b";"^$GetLine$";R)$>0 ^!Set %A%=1 ; Condition #2: at least 2 upper characters in line ^!If ^$StrPos("[[:upper:]][[:alnum:]]*[[:upper:]]";"^$GetLine$";R)$>0 ^!Set %B%=1 ; Condition #3: at least 2 lower letters in line ^!If ^$StrPos("[[:lower:]][[:alnum:]]*[[:lower:]]";"^$GetLine$";R)$>0 ^!Set %C%=1 ; Condition #4: at least one digit in line ^!If ^$StrPos("[09]";"^$GetLine$";R)$>0 ^!Set %D%=1 ; Condition #5: No punctuation characters or spaces in line ^!If ^$StrPos("[\x20\pP]";"^$GetLine$";R)$>0 ^!Set %E%=1 ; Logical test of all conditions *** ^!If ^$Calc(MIN(^%A%;MIN(^%B;MIN(^%C%;MIN(^%D%;1^%E%)))))$=1 Next Else Skip ; If whole expression is true then append line to %Hits% ^!Set %Hits%=^%Hits%^$GetLine$^P ^!Inc %Row% ^!If ^$GetRow$ < ^%Lines% Loop ; Output hits ^!Info [L]^%Hits% ^!ClearVariables I hope it won't get spoiled again. Your expressions were a stimulating intellectual game for me. Under certain conditions, this might still be an useful approach. Regarding that particular task, I would today rather solve it with RegEx: ^!Set %Lines%=^$GetDocListAll("^(?!.*[\x20\pP])(?=.*[09])(?=.*[[:upper:]][[:alnum:]]*[[:upper:]])(?=.*[[:lower:]][[:alnum:]]*[[:lower:]]).*";"$0\r\n")$ ^!Info [L]^%Lines% See https://regex101.com/r/uJczeL/1 Regards, Flo

