Friday 7 July 2017

String validation: let say (for Universal Id)


  • First letter should be 'R' and in UPPERCASE only.
  • string length should be upto 9-char
  • String value should start with uppercase 'R' and followed by eight numbers.
  • rest eight numbers varies in 0-9 only.


public boolean validate()
{
    boolean     ret;
    int         i = 1;
    anytype     isValid;
    str         universalId = CustTable_HSI_UniversalId.valueStr(); //let say "R012345678"
    TextBuffer  txt = new TextBuffer();

    //ret = super();

    if (char2num(universalId, i) == char2num(strUpr(universalId), i))
    {
        ret = true;
    }
    else
    {
        ret = false;
        throw Global::error("Universal Id should start with uppercase R character.");
    }

    isValid = strlen(universalId);
    if (isValid == 9)
    {
        ret = true;
    }
    else
    {
        ret = false;
        throw Global::error("Universal Id should be upto 9-character.");
        }
    isValid = strFind(universalId,'R',1,1);
    if (isValid == 1)
    {
        ret = true;
    }
    else
    {
        ret = false;
        throw Global::error("Universal ID should start with uppercase R followed by eight numbers.");
    }
    universalId = substr(universalId, 2,9);
    txt.setText(universalId);
    txt.regularExpressions(true);   // activate regular expr in search

    // Regular expression to validate only digits
    if (txt.find("^[0-9]+$"))
    {
        ret = true;
    }
    else
    {
        ret = false;
        throw Global::error("Universal ID should start with uppercase R followed by eight numbers.");
    }
    ret = super();
    return ret;
}

Happy DAXing...

String to Validate in case letter (Uppercase/ Lowercase) [Regular Expression is AX ]

I would like to share a logic puzzle that baffled me today. This may likely work in many programming languages, but obviously I am going to show you X++ code.

Problem:
Given the following string, write a job that displays a list of all the characters that are uppercase: AbDtw%@32E

Job-1:

static void findCapitalLetters(Args _args)
{
    str testStr = "R12345678";
    int i = 1;
    str character;

    character = subStr(testStr, i, 1);

    //If the character is EQUAL to it's uppercase counterpart, it must be uppercase:
    if (char2num(testStr, i) == char2num(strUpr(testStr), i))
    {
        info(strFmt("'%1' at position %2 is an uppercase letter.", character, i));
    }
}

I assumed that you would write a loop that compared each character with it’s uppercase character and if the character is equal to it’s uppercase counterpart, the character must be uppercase. Let’s try that:

Job-2:

static void findCapitalLetters(Args _args)
{
    str testStr = "AbDtw%@32E";
    int i ;
    int stringLenght = strLen(testStr);
    str character;

    for (i = 1; i <= stringLenght; i += 1)

    {
        character = subStr(testStr, i, 1);
        //If the character is EQUAL to it's uppercase counterpart, it must be uppercase:
        if (char2num(testStr, i) == char2num(strUpr(testStr), i))
        {
            info(strFmt("'%1' at position %2 is an uppercase letter.", character, i));
        }
   }
}

Output:


OOPS! The characters %, @, 3 and 2 are evaluated as uppercase; this is not what I had in mind. So I assumed (wrongly again) that the answer would be to first check if the character is a letter (if it is a number or symbol, I can just ignore it). I was thinking along the lines of adding str2IntOk()

The simple solution:
It turns out, if you reverse the question and ask, “Is this character not equal to its lower case letter?”, you get the correct answer:

Job-3:

static void findCapitalLetters(Args _args)
{
    str testStr = "AbDtw%@32E";
    int i;
    int stringLenght = strLen(testStr);
    str character;

    for (i=1; i<=stringLenght; i+=1)
    {
        character = subStr(testStr, i, 1);
        //If the character is EQUAL to it's uppercase counterpart, it must be uppercase:
        if (char2num(testStr, i) != char2num(strlwr(testStr), i))
        {
            info(strFmt("'%1' at position %2 is an uppercase letter.", character, i));
        }
    }
}

Explanation:
At first the two jobs looked the same to me. I thought the issue was with the way strLwr() and strUpr() work. It wasn’t until I examined the return values that I realized the problem is with the logical operators and not the string funtions.
Consider this table:


If the character is a letter, it has a different value for upper and lower case. If the value is a symbol or number, it doesn’t have an upper or lower case, and the same value returned as upper and lower case.
In the case of numbers and symbols, the question “Is this character not equal to its lower case letter?” has a different answer than “Is this character equal to its upper case letter?”.

Of course, in both cases the real question you should ask yourself is: “What is the problem I am trying to solve?”.

Happy DAXing....

Thursday 6 July 2017

String to Validate only Alpha-numeric [Regular Expression is AX ]

Following is an Example of Regular Expressions :

public boolean validate()
{
    boolean     ret;
    anytype     isValid;
    str         universalNum = CustTable_HSI_UniversalId.valueStr(); // let say "R12345678"
    // or str         universalNum = CustTable_HSI_UniversalId.text(); // let say "R12345678"

    TextBuffer  txt = new TextBuffer();

   // ret = super();

    isValid = strlen(CustTable_HSI_UniversalId.valueStr());
    if (isValid == 9)
    {
        ret = true;
    }
    else
    {
        ret = false;
        throw Global::error("Universal Id should be upto 9-character");
        }
    isValid = strFind(CustTable_HSI_UniversalId.valueStr(),'R',1,1);
    if (isValid == 1)
    {
        ret = true;
    }
    else
    {
        ret = false;
        throw Global::error("Universal Id should start wiith 'R' character");
    }
    universalNum = substr(universalNum, 2,9);
    txt.setText(universalNum);
    txt.regularExpressions(true);   // activate regular expr in search

    // Regular expression to validate only digits
    if (txt.find("^[0-9]+$"))
    {
        ret = true;
    }
    else
    {
        ret = false;
        throw Global::error("Universal Id should start wiith 'R' character and contains 0-9 consecutive numbers");
    }
    ret = super();
    return ret;
}

String to Validate only alphabets [Regular Expression is AX ]

Following is an Example of Regular Expressions :

static void TextBuffer_regularExpression(Args _args)
{
    TextBuffer txt = new TextBuffer();
    str msg = "ABCDXYZ";

    txt.setText(msg);
    txt.regularExpressions(true);   // activate regular expr in search

     // Regular expression to validate only digits
     if (txt.find("^[A-Z]+$"))
    {
        info("string contains only alphabets");
    }
}

String to Validate only Numbers [Regular Expression is AX ]

Following is an Example of Regular Expressions :

Job-1:

static void TextBuffer_regularExpression(Args _args)
{
    TextBuffer txt = new TextBuffer();
    str msg = "98797897";
   
    txt.setText(msg);
    txt.regularExpressions(true);   // activate regular expr in search

     // Regular expression to validate only digits
     if (txt.find("^[0-9]+$"))
    {
        info("string contains only numbers");
    }
}

Job-2:

static void TextBuffer_regularExpression(Args _args)
 {
    TextBuffer txt = new TextBuffer();
    str msg = "R12345678";

    msg = substr(msg, 2,9);
    txt.setText(msg);
    txt.regularExpressions(true);   // activate regular expr in search

    // Regular expression to validate only digits
    if (txt.find("^[0-9]+$"))
    {
        info("string contains only numbers");
    }
    else
    {
        info("string contains not only numbers");
    }
 }

Number of ways to count the records

To get a table record count in AX 2012:------

1. To get a table record through count function:

In X++, how do you get a record count in table, I don't want to use while loop.?

Select a count on the RecId.
For example: 
CustTable   custTable;

select count(RecId) from custTable;

info(strfmt('Number of customers are: %1', custTable.RecId));

2. To get records through database.numberOfRowsLoaded()


    MainAccount             mainAccountLoc;
    CompanyInfo             companyInfoLoc;
    Int                               numOfUpdatedRec;
    MainAccountLegalEntity  mainAccountLegalEntityLoc;

    companyInfoLoc.clear();
    companyInfoLoc = CompanyInfo::findDataArea(FilterByLegalEntity.valueStr());

    mainAccountLoc.clear();
    mainAccountLoc = MainAccount_ds.getFirst(1);
    
        while(mainAccountLoc)
        {
            ttsBegin;
            select forUpdate mainAccountLegalEntityLoc
                where mainAccountLegalEntityLoc.MainAccount == mainAccountLoc.RecId
                &&    mainAccountLegalEntityLoc.LegalEntity == companyInfoLoc.RecId;
            mainAccountLegalEntityLoc.DefaultDimension = MainAccountLegalEntity.DefaultDimension;
            mainAccountLegalEntityLoc.update();
            ttsCommit;
            numOfUpdatedRec= MainAccountLegalEntity_ds.numberOfRowsLoaded();
            mainAccountLoc = MainAccount_ds.getNext();                       
        }
        info(strFmt('%1',numOfUpdatedRec));

3. To get updated/ inserted records through Integer counter:

    MainAccount             mainAccountLoc;
    CompanyInfo             companyInfoLoc;
    counter                       numOfUpdatedRec;
    MainAccountLegalEntity  mainAccountLegalEntityLoc;

    companyInfoLoc.clear();
    companyInfoLoc = CompanyInfo::findDataArea(FilterByLegalEntity.valueStr());

    mainAccountLoc.clear();
    mainAccountLoc = MainAccount_ds.getFirst(1);
    if (mainAccountLoc)
    {
        while(mainAccountLoc)
        {
            ttsBegin;
            select forUpdate mainAccountLegalEntityLoc
                where mainAccountLegalEntityLoc.MainAccount == mainAccountLoc.RecId
                &&    mainAccountLegalEntityLoc.LegalEntity == companyInfoLoc.RecId;
            mainAccountLegalEntityLoc.DefaultDimension = MainAccountLegalEntity.DefaultDimension;
            mainAccountLegalEntityLoc.update();
            numOfUpdatedRec++;
            ttsCommit;
            mainAccountLoc = MainAccount_ds.getNext();
        }
        info(strFmt('%1',numOfUpdatedRec));


4. X++ code to count records through Sysquery::countTotal() in query:

Following code illustrates how we can use SysQuery::countTotal() method to get the number of records in Query.

static void Query_cntRecords(Args _args)
{
    Query                query = new Query();
    QueryRun             queryRun;
    QueryBuildDataSource qbd;
    ;
    
    qbd = query.addDataSource(tablenum(CustTable));
    queryRun = new QueryRun(query);
    
    info(strfmt("Total Records in Query %1",SysQuery::countTotal(queryRun)));  
}


Happy DAXing....