Please see the attachments for the mail merge issue. The result expected by me should have been:
But it turns out to be:
I believe the error is caused by the comparison in the field codes (i.e. <>) but I couldn't figure out where the error is. If I make a change to the data,
1A --> F1A
OR
1A --> A1
The error disappears. Here are the field codes:
Thanks for any help in advance!
You need to put double quotation marks around { Place2 } and { Place1 }, e.g.
"{ Place2 }"
As it is, when word does the comparison, it will evaluate values such as 1A, 2D etc. as the numbers 1 , 2 etc. Since your list starts with 1A, 1C, the comparison will be { IF 1 <> 1 } so the transition from 1A to 1C will be missed.
If you want to ensure that Word does a textual comparison, this is one reason. In fact in this scenario Word treats things that look like simple arithmetic expressions as such so if Place1 was called "2*4" and Place2 was called "8", you would get a match if you did not include the quotation marks.
There are other reasons why it is advisable to quote the comparands in an IF field when you want them to be treated as text. For example if you have the following, X is definitely "abc" and Y is definitely "def" .
{ SET X "abc" }{ SET abc "def" }{ SET Y "def" }{ X }{ Y }
But this will return "equal"
{ IF { X } = { Y } "equal" "not equal" }
whereas this will return "not equal"
{ IF "{ X }" = "{ Y }" "equal" "not equal" }
In other words, if a comparand is not quoted and evaluates to the name of a bookmark in the document, it is treated as a reference to the bookmark value and is dereferenced.
Related
Is there any limit on how many nesting we can use in Nested IF statement in Microsoft Word?
Also, if limit can be different based on office version?
The nesting limit is 20 in all Word versions.
I know this is old, but this may help others. You only need ONE else statement at the end. There is no need to nest. Example:
{IF { MERGEFIELD LETTERCODE } = "A" "LETTER A TEXT HERE"
}{IF { MERGEFIELD LETTERCODE } = "B" "LETTER B TEXT HERE"
}{IF { MERGEFIELD LETTERCODE } = "C" "LETTER C TEXT HERE"
}{IF { MERGEFIELD LETTERCODE } = "D" "LETTER D TEXT HERE"
"ELSE DEFAULT LETTER TEXT HERE" }
I've done 80+ versions like this.
I am still trying to work on permutation match, and I wonder if anyone has better way to do it. I want to match all patterns in an array in any order, i.e., match permutations of items (string or other objects) in an array. E.g., if array is (1,2,3), then it is true if a string contains 1 and 2 and 3 in any order; i.e, true if a string contains permutation of (1,2,3).
What I have now is this:
my #x = < one eins uno yi two zwei dos er one one one two two two >;
my #z = < one eins uno yi two zwei dos er one one one two two two foo >;
my $y = "xxx one eins uno yi two zwei dos er xxx";
sub matchAllWords($aString, #anArray) {
my $arraySize = #anArray.elems;
if $arraySize == 0 { False; }
elsif $arraySize == 1 {
($aString.match(/:i "#anArray[0]" /)).Bool;
} else {
my $firstCheck = ($aString.match(/:i "#anArray[0]"/)).Bool;
if $firstCheck {
$firstCheck
and
(matchAllWords($aString, #anArray[1..*]));
} else {
return False;
}
}
}
say matchAllWords($y, #x);
# result is True, but it should NOT be True because $y should not
# match permutations of #x which contains multiple identical elements
# of "one" and "two"
say matchAllWords($y, #z); # False as expected;
The problems is that my function matches all unique words in the array, but is unable to differentiate permutations of duplicate words. I can add more and more codes to tell if a word has been matched, but more codes to accomplish a simple idea, "permutation match", is un-perl-ly. Any suggestions? Thanks
New answer
Based on everyone's comments, here's a restatement of the problem as I now understand it, followed by a new solution:
Test that Y, a string, contains all of the strings in Z, a Bag (multiset) of strings, with correct copy count / multiplicity.
my \Z = < one eins uno yi two zwei dos er two > .Bag ;
my \Y = "xxx one eins uno yi two zwei dos er two xxx" ;
sub string-matches-bag ($string, $bag) {
for $bag.kv -> $sub-string, $copy-count {
fail unless ($string ~~ m:g/ $sub-string /).elems == $copy-count
}
True
}
say string-matches-bag Y, Z
Old answer
say so $y.words.all eq #z.any
An explanation for this line of code is in the last part of this answer.
I found your question pretty confusing. But I'm hopeful this answer is either what you want or at least enough to move things in the right direction.
I found your data confusing. There are two 'xxx' words in your $y but none in either array. So that bit can't match. There's a 'foo' in your #z. Was that supposed to be 'xxx'? There's a 'one' in your $y but both arrays have at least two 'one's. Is that an issue?
I found your narrative confusing too.
For this answer I've assumed that #z has a xxx at the end, and that the key comment is:
a simple idea, "permutation match"
say so $y.words.all eq #z.any
so returns the boolean evaluation (True or False) of the expression on its right.
The expression on so's right uses Junctions. An English prose summary of it is 'all of the "words" in $y, taken one at a time, are string equal to at least one element of #z'.
Is this the simple solution you're asking for?
I have few similar questions about expressions. I marked them as Q1, Q2 and Q3 for convenience.
First. As stated in the docs,
Variable names in an expression are not enclosed in percent signs (except for pseudo-arrays and other double references). Consequently, literal strings must be enclosed in double quotes to distinguish them from variables.Source
As I understand, this means we should write code like this:
a = aaa
b = zzz
if (a = "aaa" or b = "bbb")
MsgBox, It works!
However, this seems also works:
a = aaa
b = zzz
if (%a% = aaa or %b% = bbb)
MsgBox, It works!
Is there some drawbacks in the second way? (Q1)
One possible drawback, which I found myself, is that second method will not work if variable contains only digits. This will not work:
a = 111
b = 999
if (%a% = 111 or %b% = 222)
MsgBox, It works!
Why it stopped worked now? (Q2)
And also, if variable contains only digits, there seems no need to quote it's value in expression:
a = 111
if (a = "111") ; Also works for a = "aaa"
MsgBox, It works!
a = 111
if (a = 111) ; It will not work for a = "aaa". We forced to us quote signs if var contains letters.
MsgBox, It works too.
Why second way (if (a = 111)) works and should or should not we avoid it? (Q3).
(Q1)
If a variable is enclosed in percent signs within an expression (in your example %a%), whatever that variable contains is assumed to be the name or partial name of another variable.
This also works
a = aaa
b = zzz
if (%a% = a or %h% = cc)
MsgBox, It works!
because the values of the vars %a% and %h% are not specified.
(Q2)
If both var and value are purely numeric, they will be compared as numbers rather than as strings.
Otherwise, they will be compared alphabetically as strings (that is, alphabetical order will determine whether var is greater, equal, or less than value).
(Q3)
Only literal strings must be enclosed in double quotes.
If the variable contains only digits, there is no need to quote.
I have a flex-bison project in which I need to support a few string operators, and operator '^' means reverse a string and operator [i] means return index i in the string.
correct input and output for example :
input : ^"abc"[0] ---> correct output: "c", my output: "a"
that's because first I want to reverse it("cba") and then take the 0 index ("cba"[0] is c).
Now, I don't know how to do that precedence, so my code outputs "a" since it first takes "abc"[0]--> "a" and then reverses it-->"a". as of now I have in my bison file:
%left STR MINI
%left '^'
substring:
STR MINI { //THIS IS DONE FIRST, SUBSTRING
$$ = substringFind($1,$2,$2,temp);
}
| '^' substring { //BUT I WANT THIS (REVERSING) TO BE FIRST
$$ = reverseStrings($2,temp);
}
;
how do I change that precedence? I don't really understand the precedence rules, it was very easy with plus (+) before multiple (*) but with those operators I don't really know how to work with it.
ANY HELP...?
You need separate productions, not alternates within the same production, something like:
string
: substring
;
substring
: reverse MINI { ... }
| reverse
;
reverse
: "^" reverse { ... }
| STR
;
I've got a related thread in the site(My lex pattern doesn't work to match my input file, how to correct it?)
The problems I met, is about how "greedy" lex will do pattern match, e.g. I've got my lex file:
$ cat b.l
%{
#include<stdio.h>
%}
%%
"12" {printf("head\n");}
"34" {printf("tail\n");}
.* {printf("content\n");}
%%
What I wish to say is, when meet "12", print "head"; when meet "34", print "tail", otherwise print "content" for the longest match that doesn't contain either "12" or "34".
But the fact was, ".*" was a greedy match that whatever I input, it prints "content".
My requirement is, when I use
12sdf2dfsd3sd34
as input, the output should be
head
content
tail
So seems there're 2 possible ways:
1, To specify a match priority for ".*", it should work only when neither "12" and "34" works to match. Does lex support "priority"?
2, to change the 3rd expression, as to match any contiguous string that doesn't contain sub-string of "12", or "34". But how to write this regular expression?
Does (f)lex support priority?
(F)lex always produces the longest possible match. If more than one rule matches the same longest match, the first one is chosen, so in that case it supports priority. But it does not support priority for shorter matches, nor does it implement non-greedy matching.
How to match a string which does not contain one or more sequences?
You can, with some work, create a regular expression which matches a string not containing specified substrings, but it is not particularly easy and (f)lex does not provide a simple syntax for such regular expressions.
A simpler (but slightly less efficient) solution is to match the string in pieces. As a rough outline, you could do the following:
"12" { return HEAD; }
"34" { if (yyleng > 2) {
yyless(yyleng - 2);
return CONTENT;
}
else
return TAIL;
}
.|\n { yymore(); }
This could be made more efficient by matching multiple characters when there is not chance of skipping a delimiter; change the last rule to:
.|[^13]+ { yymore(); }
yymore() causes the current token to be retained, so that the next match appends to the current token rather than starting a new token. yyless(x) returns all but the first x characters to the input stream; in this case, that is used to cause the end delimiter 34 to be rescanned after the CONTENT token is identified.
(That assumes you actually want to tokenize the input stream, rather than just print a debugging message, which is why I called it an outline solution.)