Find / search case sensitive - axapta

Is it possible to do a case sensitive find (search) in Dynamics AX 2009?
For example, when I am searching for "address", I don't want to see "Address" in the results.

Jan,
There IS a way to do it using standard Axapta X++. When you use the find screen there is a tab called 'Filter' where you can place code to do the filtering (no need to complete the fields on the name & location tab). The below code is for illustration purposes only as the below code is not complete and has not been finalised (I leave that to you).
str toMatch = 'Address';
str string;
str char, charMatch;
int i, pos;
boolean ret;
;
pos = strScan(_treeNodeName, toMatch, 1, strLen(_treeNodeName));
string = subStr(_treeNodeName, pos, strLen(toMatch));
if (string)
{
ret = true;
for (i=1;i<=strLen(toMatch);i++)
{
char = subStr(toMatch, i, 1);
charMatch = subStr(string, i, 1);
if (char2num(char,1) != char2num(charMatch,1))
{
ret = false;
}
}
if (ret)
{
return ret;
}
}
pos = strScan(_treeNodeSource, toMatch, 1, strLen(_treeNodeSource));
string = subStr(_treeNodeSource, pos, strLen(toMatch));
if (string)
{
ret = true;
for (i=1;i<=strLen(toMatch);i++)
{
char = subStr(toMatch, i, 1);
charMatch = subStr(string, i, 1);
if (char2num(char,1) != char2num(charMatch,1))
{
ret = false;
}
}
if (ret)
{
return ret;
}
}
return false;

If you have a look at the Find form window that appears when you do a find, look at the properties, this helps you narrow you down your search, unsure about a like-for-like exact match i.e. "address" and blocking out "Address".

No you cannot.
As mentioned in this answer, the find form uses the match method, which is documented on msdn here.
To quote MSDN;
Remarks
The system does not differentiate between lower and upper case.

Related

How to count statements in C ignoring the comments

int Emptylines(FILE *fp);
int Numberofstatements(FILE *fp);
int main() {
FILE *fp = NULL;
FILE *fp1 = NULL;
int n1, n2;
char fname[255], fname1[255];
printf("Enter file name for reading");
fflush(stdin);
scanf("%s", &fname);
fp = fopen(fname, "r");
if (fp == NULL) {
printf("File with name %s couldn't be open", fname);
exit(1);
}
n1 = Emptylines(fp); // this is for empty lines
n2 = Numberofstatements(fp);
printf("Insert file name for writing");
fflush(stdin);
scanf("%s", &fname1);
fp1 = fopen(fname1, "w+");
fprintf(fp1, "The number of empty lines=%d", n1);
fprintf(fp1, "The number of statements=%d", n2);
fclose(fp);
fclose(fp1);
return 0;
}
int Numberofstatements(FILE *fp) {
char line[128];
int nofstatements = 0;
while (fgets(line, sizeof line, fp) != NULL) {
if (strstr(line, "if") != 0)
nofstatements++;
}
return nofstatements;
}
I need to count all statements like if, do, while, break, etc. as well as empty lines and then save the result in a new file. I succeed in counting the empty lines but I have no idea how to count the statements. I tried 2 different ways but both failed.
I also need to ignore comments while reading the code, so if there is a for, while, etc. in the comments it shouldn't be counted.
A very basic answer addressing the fundamental issue (although there are others).
When you call int Numberofstatements(FILE *fp) you already reached the end of file in int Emptylines(FILE *fp); so you must add the statement
rewind(fp);
before trying to parse the file for a second time. Good luck with developing this.
OP asks: "Any ideas ?"
To do properly, suggest reading 1 char at a time. Keep track if you are in 1) on an include line, 2) inside a " " 3) inside a ' ' 4) in a // comment 5) inside a /* comment or 6) just plain code (watch for escape sequences). When in plain code look for the keywords do, while, etc. and all the while count the '\n'.
To do correctly - this is not an easy task - about 10x the code you have posted.
Sample beginning of a state machine.
state = plaincode;
while ((c = getc()) != EOF) {
switch (state) {
slashslash_commnet:
if (c == '\n) state = plaincode;
break;
plaincode:
if (c == '/') {
c2 = getc();
if (c2 == '/') { state = slashslash_commnet; break; }
else if (c2 == '*') { state = slashstar_commnet: break; }
else unget(c2);
else if (c == '\"') {
...

Adding Firebase data, dots and forward slashes

I try to use firebase db,
I found very important restrictions, which are not described in firebase help or FAQ.
First problem is that symbol: dot '.' prohibited in keys,
i.e. firebase reject (with unknown reason) next:
nameRef.child('Henry.Morgan#caribbean.sea').set('Pirat');
Second problem with forward slashes in your keys '/',
when you try to add key like this
{'02/10/2013': true}
In firebase you can see:
'02': {
'10': {
'2013': true
}
}
Have you got any ideas how to solve it (automatically)?
May be set some flag that it is string key with all symbols?
Of course, I can parse/restore data every time before write and after read, but...
By the way '.' '/' - all restricted symbols for firebase ?
The reason that adding a child 02/10/2013 creates a structure in Firebase is because the forward slashes are resulting in the creation of a new level.
So the line I assume you are using something similar to: firebaseRef.child('02/10/2013').set(true) is equivalent to firebaseRef.child('02').child('10').child('2013').set(true).
To avoid the problems of not being able to use the following characters in reference key names (source),
. (period)
$ (dollar sign)
[ (left square bracket)
] (right square bracket)
# (hash or pound sign)
/ (forward slash)
we can use one of JavaScript's built in encoding functions since as far as I can tell, Firebase does not provide a built in method to do so. Here's a run-through to see which is the most effective for our purposes:
var forbiddenChars = '.$[]#/'; //contains the forbidden characters
escape(forbiddenChars); //results in ".%24%5B%5D%23/"
encodeURI(forbiddenChars); //results in ".%24%5B%5D%23%2F"
encodeURIComponent(forbiddenChars); //results in ".%24%5B%5D%23%2F"
Evidently, the most effective solution is encodeURIComponent. However, it doesn't solve all our problems. The . character still poses a problem as shown by the above test and trying to encodeURIComponent your test e-mail address. My suggestion would be to chain a replace function after the encodeURIComponent to deal with the periods.
Here's what the solution would look like for your two example cases:
encodeURIComponent('Henry.Morgan#caribbean.sea').replace(/\./g, '%2E') //results in "Henry%2EMorgan%40caribbean%2Esea"
encodeURIComponent('02/10/2013'); //results in "02%2F10%2F2013"
Since both the final results are safe for insertion into a Firebase as a key name, the only other concern is decoding after reading from a Firebase which can be solved with replace('%2E', '.') and a simple decodeURIComponent(...).
I faced the same problem myself, and I have created firebase-encode for this purpose.
Unlike the chosen answer, firebase-encode encodes only unsafe characters (./[]#$) and % (necessary due to how encoding/decoding works).
It leaves other special characters that are safe to be used as firebase key while encodeURIComponent will encode them.
Here's the source code for details:
// http://stackoverflow.com/a/6969486/692528
const escapeRegExp = (str) => str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');
const chars = '.$[]#/%'.split('');
const charCodes = chars.map((c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
const charToCode = {};
const codeToChar = {};
chars.forEach((c, i) => {
charToCode[c] = charCodes[i];
codeToChar[charCodes[i]] = c;
});
const charsRegex = new RegExp(`[${escapeRegExp(chars.join(''))}]`, 'g');
const charCodesRegex = new RegExp(charCodes.join('|'), 'g');
const encode = (str) => str.replace(charsRegex, (match) => charToCode[match]);
const decode = (str) => str.replace(charCodesRegex, (match) => codeToChar[match]);
I wrote this for Java (since I came here expecting a java implementation):
public static String encodeForFirebaseKey(String s) {
return s
.replace("_", "__")
.replace(".", "_P")
.replace("$", "_D")
.replace("#", "_H")
.replace("[", "_O")
.replace("]", "_C")
.replace("/", "_S")
;
}
public static String decodeFromFirebaseKey(String s) {
int i = 0;
int ni;
String res = "";
while ((ni = s.indexOf("_", i)) != -1) {
res += s.substring(i, ni);
if (ni + 1 < s.length()) {
char nc = s.charAt(ni + 1);
if (nc == '_') {
res += '_';
} else if (nc == 'P') {
res += '.';
} else if (nc == 'D') {
res += '$';
} else if (nc == 'H') {
res += '#';
} else if (nc == 'O') {
res += '[';
} else if (nc == 'C') {
res += ']';
} else if (nc == 'S') {
res += '/';
} else {
// this case is due to bad encoding
}
i = ni + 2;
} else {
// this case is due to bad encoding
break;
}
}
res += s.substring(i);
return res;
}
Character limitations are documented at https://www.firebase.com/docs/creating-references.html - you cannot use '.', '/', '[', ']', '#', and '$' in key names. There is no automatic way of escaping these characters, I'd recommend avoiding their use altogether or creating your own escaping/unescaping mechanism.
If you're using Swift 3, this works for me (try it in a playground):
var str = "this.is/a#crazy[string]right$here.$[]#/"
if let strEncoded = str.addingPercentEncoding(withAllowedCharacters: .alphanumerics) {
print(strEncoded)
if let strDecoded = strEncoded.removingPercentEncoding {
print(strDecoded)
}
}
I got annoyed with this problem so I took the answer from #sushain97 (thanks!) and built a deep encoder/decoder.
https://www.npmjs.com/package/firebase-key-encode
Basic usage:
var firebaseKeyEncode = require('firebase-key-encode');
firebaseKeyEncode.encode('my.bad.key');
// Output: my%2Ebad%2Ekey
Deep Usage:
var firebaseKeyEncode = require('firebase-key-encode');
var badTree = {
"pets": [
{
"jimmy.choo": 15}
],
"other.key": 5
}
firebaseKeyEncode.deepEncode(badTree);
// Output: {
// "pets": [
// {
// "jimmy%2Echoo": 15}
// ],
// "other%2Ekey": 5
// }
Personally, I found a simple and easy hack for this same problem I encountered
I took the dateTime string and convert it using replace('/','|')
the result will be something like this 2017|07|24 02:39:37 instead of 2017/07/24 02:39:37.
Even though it is not what OP asks,
but in my experience rather than using such dubious keys it is better to let .push() create an id,
and other things - e-mail, date etc. save as content of the dedicated fields.
$id: {
email: "Henry.Morgan#caribbean.sea"
}
P.S. Don't try to save volume by inserting what should be content into the key.
Premature optimization is the root of all evil (c).
Efficient C# implementation (for Unity and .net). Based on the answer from #josue.0.
public static string EncodeFirebaseKey(string s) {
StringBuilder sb = new StringBuilder();
foreach (char c in s) {
switch (c) {
case '_':
sb.Append("__");
break;
case '$':
sb.Append("_D");
break;
case '.':
sb.Append("_P");
break;
case '#':
sb.Append("_H");
break;
case '[':
sb.Append("_O");
break;
case ']':
sb.Append("_C");
break;
case '/':
sb.Append("_S");
break;
default:
sb.Append(c);
break;
}
}
return sb.ToString();
}
public static string DecodeFirebaseKey(string s) {
StringBuilder sb = new StringBuilder();
bool underscore = false;
for (int i = 0; i < s.Length; i++) {
if (underscore) {
switch (s[i]) {
case '_':
sb.Append('_');
break;
case 'D':
sb.Append('$');
break;
case 'P':
sb.Append('.');
break;
case 'H':
sb.Append('#');
break;
case 'O':
sb.Append('[');
break;
case 'C':
sb.Append(']');
break;
case 'S':
sb.Append('/');
break;
default:
Debug.LogWarning("Bad firebase key for decoding");
break;
}
underscore = false;
} else {
switch (s[i]) {
case '_':
underscore = true;
break;
default:
sb.Append(s[i]);
break;
}
}
}
return sb.ToString();
}
Python implementation
_escape = {'&': '&&',
'$': '&36',
'#': '&35',
'[': '&91',
']': '&93',
'/': '&47',
'.': '&46'}
_unescape = {e: u for u, e in _escape.items()}
def escape_firebase_key(text):
return text.translate(str.maketrans(_escape))
def unescape_firebase_key(text):
chunks = []
i = 0
while True:
a = text[i:].find('&')
if a == -1:
return ''.join(chunks + [text[i:]])
else:
if text[i+a:i+a+2] == '&&':
chunks.append('&')
i += a+2
else:
s = text[i+a:i+a+3]
if s in _unescape:
chunks.append(text[i:i+a])
chunks.append(_unescape[s])
i += a+3
else:
raise RuntimeError('Cannot unescape')
And a few test cases:
test_pairs = [('&hello.', '&&hello&46'),
('&&&', '&&&&&&'),
('some#email.com', 'some#email&46com'),
('#$[]/.', '&35&36&91&93&47&46')]
for u, e in test_pairs:
assert escape_firebase_key(u) == e, f"escaped '{u}' is '{e}', but was '{escape_firebase_key(u)}'"""
assert unescape_firebase_key(e) == u, f"unescaped '{e}' is '{u}', but was '{unescape_firebase_key(e)}'"
try:
unescape_firebase_key('&error')
assert False, 'Must have raised an exception here'
except RuntimeError as ex:
assert str(ex) == 'Cannot unescape'
const encodeKey = s => s.replace(/[\.\$\[\]#\/%]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase())
const decodeKey = s => s.replace(/%(2E|24|5B|5D|23|2F|25)/g, decodeURIComponent)
console.log(encodeKey('.$[]#/%23')) // %2E%24%5B%5D%23%2F%2523
console.log(decodeKey(encodeKey('.$[]#/%23'))) // .$[]#/%23
import re
import urllib.parse
encode_key = lambda s: re.sub('[\.\$\[\]#\/%]', lambda c: f'%{ord(c.group()):X}', s)
decode_key = lambda s: re.sub('%(2E|24|5B|5D|23|2F|25)', lambda c: urllib.parse.unquote(c.group()), s)
print(encode_key('.$[]#/%23')) # %2E%24%5B%5D%23%2F%2523
print(decode_key(encode_key('.$[]#/%23'))) # .$[]#/%23

Is it possible to use a Kleene Operator for Flex Formatters?

is it possible to use a Kleene Operator (Kleene Star) for the Formatters?
I want to use a phoneFormatter, which puts a minus after the 5th number and afterwards it should be possible to have a variable number of numbers.
E.g.: 0172-555666999, 0160-44552 etc.
That is how I started, but I don't know which character belongs after the last hash (it is not a star, I already tried it ;-) ):
<fx:Declarations>
<mx:PhoneFormatter id="mPhoneFormat"
formatString="####-#"/>
</fx:Declarations>
The default PhoneFormatter expects the input string to have the same number of characters as the format string. They don't support regular expression patterns (like * to match the element zero or more times).
However, it's pretty easy to make your own formatter. To do this, I extended the PhoneFormatter class and overrode its format() method. I copied and pasted the original format() method and made the following modifications:
comment out the code that compared the length of the source string with the length of the format string
compare the length of the formatted string. If the original string is longer, append the remaining chars from the original string to the formatted string.
This probably won't handle all of your use cases, but it should be pretty straightforward to modify this to your needs.
package
{
import mx.formatters.PhoneFormatter;
import mx.formatters.SwitchSymbolFormatter;
public class CustomPhoneNumberFormatter extends PhoneFormatter
{
public function CustomPhoneNumberFormatter()
{
super();
}
override public function format(value:Object):String
{
// Reset any previous errors.
if (error)
error = null;
// --value--
if (!value || String(value).length == 0 || isNaN(Number(value)))
{
error = defaultInvalidValueError;
return "";
}
// --length--
var fStrLen:int = 0;
var letter:String;
var n:int;
var i:int;
n = formatString.length;
for (i = 0; i < n; i++)
{
letter = formatString.charAt(i);
if (letter == "#")
{
fStrLen++;
}
else if (validPatternChars.indexOf(letter) == -1)
{
error = defaultInvalidFormatError;
return "";
}
}
// if (String(value).length != fStrLen)
// {
// error = defaultInvalidValueError;
// return "";
// }
// --format--
var fStr:String = formatString;
if (fStrLen == 7 && areaCode != -1)
{
var aCodeLen:int = 0;
n = areaCodeFormat.length;
for (i = 0; i < n; i++)
{
if (areaCodeFormat.charAt(i) == "#")
aCodeLen++;
}
if (aCodeLen == 3 && String(areaCode).length == 3)
{
fStr = String(areaCodeFormat).concat(fStr);
value = String(areaCode).concat(value);
}
}
var dataFormatter:SwitchSymbolFormatter = new SwitchSymbolFormatter();
var source:String = String(value);
var returnValue:String = dataFormatter.formatValue(fStr, value);
if (source.length > returnValue.length)
{
returnValue = returnValue + source.substr(returnValue.length-1);
}
return returnValue;
}
}
}

X++ passing current selected records in a form for your report

I am trying to make this question sound as clear as possible.
Basically, I have created a report, and it now exists as a menuitem button so that the report can run off the form.
What I would like to do, is be able to multi-select records, then when I click on my button to run my report, the current selected records are passed into the dialog form (filter screen) that appears.
I have tried to do this using the same methods as with the SaleLinesEdit form, but had no success.
If anyone could point me in the right direction I would greatly appreciate it.
Take a look at Axaptapedia passing values between forms. This should help you. You will probably have to modify your report to use a form for the dialog rather than using the base dialog methods of the report Here is a good place to start with that!
Just wanted to add this
You can use the MuliSelectionHelper class to do this very simply:
MultiSelectionHelper selection = MultiSelectionHelper::createFromCaller(_args.caller());
MyTable myTable = selection.getFirst();
while (myTable)
{
//do something
myTable = selection.getNext();
}
Here is the resolution I used for this issue;
Two methods on the report so that when fields are multi-selected on forms, the values are passed to the filter dialog;
private void setQueryRange(Common _common)
{
FormDataSource fds;
LogisticsControlTable logisticsTable;
QueryBuildDataSource qbdsLogisticsTable;
QueryBuildRange qbrLogisticsId;
str rangeLogId;
set logIdSet = new Set(Types::String);
str addRange(str _range, str _value, QueryBuildDataSource _qbds, int _fieldNum, Set _set = null)
{
str ret = _range;
QueryBuildRange qbr;
;
if(_set && _set.in(_Value))
{
return ret;
}
if(strLen(ret) + strLen(_value) + 1 > 255)
{
qbr = _qbds.addRange(_fieldNum);
qbr.value(ret);
ret = '';
}
if(ret)
{
ret += ',';
}
if(_set)
{
_set.add(_value);
}
ret += _value;
return ret;
}
;
switch(_common.TableId)
{
case tableNum(LogisticsControlTable):
qbdsLogisticsTable = element.query().dataSourceTable(tableNum(LogisticsControlTable));
qbrLogisticsId = qbdsLogisticsTable.addRange(fieldNum(LogisticsControlTable, LogisticsId));
fds = _common.dataSource();
for(logisticsTable = fds.getFirst(true) ? fds.getFirst(true) : _common;
logisticsTable;
logisticsTable = fds.getNext())
{
rangeLogId = addrange(rangeLogId, logisticsTable.LogisticsId, qbdsLogisticsTable, fieldNum(LogisticsControlTable, LogisticsId),logIdSet);
}
qbrLogisticsId.value(rangeLogId);
break;
}
}
// This set the query and gets the values passing them to the range i.e. "SO0001, SO0002, SO000£...
The second methods is as follows;
private void setQueryEnableDS()
{
Query queryLocal = element.query();
;
}
Also on the init method this is required;
public void init()
{
;
super();
if(element.args() && element.args().dataset())
{
this.setQueryRange(element.args().record());
}
}
Hope this helps in the future for anyone else who has the issue I had.

How to match text in string in Arduino

I have some issues with Arduino about how to match text.
I have:
String tmp = +CLIP: "+37011111111",145,"",,"",0
And I am trying to match:
if (tmp.startsWith("+CLIP:")) {
mySerial.println("ATH0");
}
But this is not working, and I have no idea why.
I tried substring, but the result is the same. I don't know how to use it or nothing happens.
Where is the error?
bool Contains(String s, String search) {
int max = s.length() - search.length();
for (int i = 0; i <= max; i++) {
if (s.substring(i) == search) return true; // or i
}
return false; //or -1
}
Otherwise you could simply do:
if (readString.indexOf("+CLIP:") >=0)
I'd also recommend visiting:
https://www.arduino.cc/en/Reference/String
I modified the code from gotnull. Thanks to him to put me on the track.
I just limited the search string, otherwise the substring function was not returning always the correct answer (when substrign was not ending the string). Because substring search always to the end of the string.
int StringContains(String s, String search) {
int max = s.length() - search.length();
int lgsearch = search.length();
for (int i = 0; i <= max; i++) {
if (s.substring(i, i + lgsearch) == search) return i;
}
return -1;
}
//+CLIP: "43660417XXXX",145,"",0,"",0
if (strstr(command.c_str(), "+CLIP:")) { //Someone is calling
GSM.print(F("ATA\n\r"));
Number = command.substring(command.indexOf('"') + 1);
Number = Number.substring(0, Number.indexOf('"'));
//Serial.println(Number);
} //End of if +CLIP:
This is how I'm doing it. Hope it helps.
if (tmp.startsWith(String("+CLIP:"))) {
mySerial.println("ATH0");
}
You can't put the string with quotes only you need to cast the variable :)

Resources