The Character Service Class
The service class
Character processes character strings in various ways. Internally, this class assumes that all character strings are sequences of 8-bit unsigned bytes -- i.e. with values in the range 0-255. Though not required all current implementations of this class use ASCII or UTF-8 variable length encoding and the descriptions of the methods assume that encoding.
Character.Compare Method
Declaration
<Method id="Compare" type="Integer" opcode="SCM.Character_Compare">
<Argument id="string1" type="String" status="ByVal" />
<Argument id="string2" type="String" status="ByVal" />
<Argument id="nCompare" type="Integer" status="ByVal" />
</Method>
The
Character.Compare method does a case-insensitive comparison between two character vectors. This is a bounded comparison. The null-character is treated exactly like any other special character. If all characters within the specified range are identical, up to case distinctions, then the method returns a zero. If two characters within the specified range disagree, then the value of the character in the first vector minus that in the second vector is returned. The parameters are:
Parameter | Description |
string1 | contains the first character vector in the comparison. |
string2 | contains the second character vector in the comparison. |
nCompare | specifies the number of characters to be compared. |
Note that the characters within the strings are retrieved and compared as byte values in the range 0 to 255.
This method is used by the engine when it evaluates the relational arguments applied to the string type. The following code shows this as well.
string name1 = "Fred";
string name2 = "Freddy";
Write.Line "Unit test for Character.Compare() Method"
if(name1 != name2) Write.Line(name1 + " does not equal " + name2);
Write.Line("Character.Compare(name1,name2,6) = " + Character.Compare(name1,name2,6));
Write.Line("Character.Compare(name2,name1,6) = " + Character.Compare(name2,name1,6));
Write.Line("Character.Compare(name1,name2,4) = " + Character.Compare(name1,name2,4));
This code produces the following output.
Unit test for Character.Compare() Method
Fred does not equal Freddy
Character.Compare(name1,name2,6) = -68
Character.Compare(name2,name1,6) = 68
Character.Compare(name1,name2,4) = 0
The inequality check fails because the comparison is done over the length of the longest string. The return value is the value in the first string minus the value in the second string as the above shows. Finally, limiting the comparison to the first four characters reports a zero difference.
Character.FindFirst Method
Declaration
<Method id="FindFirst" type="Integer" opcode="SCM.Character_FindFirst" >
<Argument id="source" type="String" status="ByVal" />
<Argument id="iStart" type="integer" status="ByVal"/>
<Argument id="substr" type="String" status="ByVal" />
</Method>
The
Character.FindFirst method finds the first occurrence of substring in a string starting at the front of the string. All character comparisons are case insensitive. It returns when it finds a first occurrence or when it reaches the end of the string. Its parameters are:
Parameter | Description |
source | contains the string which is being searched. |
iStart | specifies the position relative to zero of the start of the search. |
substr | contains the substring which is being searched for. |
If all characters within the substring are identical to a sequence of characters within the string, up to case distinctions, then the method returns the position, relative to one, of the start of the matching sequence in the string. If no matching sequence can be located in the string, then a zero is returned. The following code shows this.
string input;
int index;
Write.Line "Unit test for Character.FindFirst() Method"
input = "\fkgtest\FmStocks\src\WebSite\t_begin_cart.asp";
index = Character.FindFirst(input,0,"\");
Write.Line("Index of \ in <" + input + "> is " + index);
input = Character.Replace(input,"\","_");
index = Character.FindFirst(input,0,"\");
Write.Line("Index of \ in <" + input + "> is " + index);
As the output of the code shows
Unit test for Character.FindFirst() Method
Index of \ in <\fkgtest\FmStocks\src\WebSite\t_begin_cart.asp> is 1
Index of \ in <_fkgtest_FmStocks_src_WebSite_t_begin_cart.asp> is 0
The first backslash found in the string is the 1st character, but when backslashes are replaced by underscores it is zero since there are no more backslashes.
Character.HexiDecimal Method
The
HexiDecimal method converts an unsigned integer value into a character string using hexadecimal, decimal, octal, or binary notation.
<Method id="HexiDecimal" type="string" opcode="SCM.Character_HexiDecimal" >
<Argument id="iValue" type="Integer" status="ByVal" />
<Argument id="base" type="Integer" status="ByVal" />
</Method>
Note that the decimal, octal, and binary notation digits are simply subsets of the hexadecimal digits. Its parameters are:
Parameter | Description |
iValue | is the integer value to be converted. |
base | is the base to be used -- 2, 8, 10, or 16. |
The method returns the string containing the character representation. This can be seen in the following code.
void TestHexidecimal
{
int value = 59;
Write.Line "Unit test for Character.HexiDecimal() Method"
Write.Line("Representation of " + value + " as base 2 is: " + Character.HexiDecimal(value,2));
Write.Line("Representation of " + value + " as base 8 is: " + Character.HexiDecimal(value,8));
Write.Line("Representation of " + value + " as base 10 is: " + Character.HexiDecimal(value,10));
Write.Line("Representation of " + value + " as base 16 is: " + Character.HexiDecimal(value,16));
}
This method produces the following result.
Unit test for Character.HexiDecimal() Method
Representation of 59 as base 2 is: 111011
Representation of 59 as base 8 is: 73
Representation of 59 as base 10 is: 59
Representation of 59 as base 16 is: 3b
Character.Insert Method
The
Insert method inserts a substring into a base string starting at a zero-based offset.
<Method id="Insert" type="string" opcode="SCM.Character_Insert" >
<Argument id="source" type="String" status="ByVal" />
<Argument id="iStart" type="integer" status="ByVal"/>
<Argument id="subStr" type="String" status="ByVal" />
</Method>
Its parameters are:
Parameter | Description |
source | base string that receives the substring |
iStart | zero-based offset in the base string where the insertion is to begin |
subStr | substring being inserted |
The method returns the result of the insertion. The following code shows how the "?" characters in an SQL select string can be replaced by the "@" character concatenated with an index value.
void TestInsert()
{
string oldSQL = "select * from accounts where accountID < ? and FirstName like ?";
string newSQL = oldSQL;
int index;
int iPos;
int lPos;
Write.Line "Unit test for Character.Insert() Method"
iPos = 0;
for(index = 0; index < 10; index = index + 1)
{
lPos = Character.FindFirst(newSQL,iPos,"?");
if(!lPos) break;
iPos = iPos + lPos - 1;
newSQL = Character.Remove(newSQL,iPos,1);
newSQL = Character.Insert(newSQL,iPos,"@" + index);
}
Write.Line("OLD: " + oldSQL);
Write.Line("NEW: " + newSQL);
}
The output of the method shows the original string and its revised version.
Unit test for Character.Insert() Method
OLD: select * from accounts where accountID < ? and FirstName like ?
NEW: select * from accounts where accountID < @0 and FirstName like @1
Character.Remove Method
The
Remove method forms a new string by removing a specified number of characters from a string starting at a zero-based offset into the string.
<Method id="Remove" type="string" opcode="SCM.Character_Remove" >
<Argument id="strValue" type="string" status="ByVal"/>
<Argument id="iStart" type="integer" status="ByVal"/>
<Argument id="length" type="integer" status="ByVal"/>
</Method>
Its parameters are:
Parameter | Description |
strValue | contains the string from which characters are to be removed |
iStart | specifies the zero-based offset of the first character to be removed. |
length | specifies the number of characters to be removed. |
The method returns the newly formed string. The code below shows how it can be used to remove certain name-value pairs from a connection string.
void TestRemove()
{
int iPos;
int semi;
string dbs = "UID=stocks_login;PWD=password;Database=stocks;" + "Server=GMI-CS-01.gmi.local;Driver={SQL Server};" + "DSN='';";
string connect = dbs;
Write.Line "Unit test for Character.Remove() Method"
iPos = Character.FindFirst(connect,0,"Driver=");
if(iPos)
{
iPos = iPos - 1;
semi = Character.FindFirst(connect,iPos,";");
if(semi)
{
connect = Character.Remove(connect,iPos,semi);
}
}
iPos = Character.FindFirst(connect,0,"DSN=");
if(iPos)
{
iPos = iPos - 1;
semi = Character.FindFirst(connect,iPos,";");
if(semi)
{
connect = Character.Remove(connect,iPos,semi);
}
}
Write.Line("OLD: " + dbs);
Write.Line("NEW: " + connect);
}
The output of the method shows the connection string before and after the removal.
Unit test for Character.Remove() Method
OLD: UID=stocks_login;PWD=password;Database=stocks;Server=GMI-CS-01.gmi.local;Driver={SQL Server};DSN='';
NEW: UID=stocks_login;PWD=password;Database=stocks;Server=GMI-CS-01.gmi.local;
Character.Replace Method
The
Replace method forms a new string from an existing one in which all occurrences of a specified substring have been replace by a new substring.
<Method id="Replace" type="string" opcode="SCM.Character_Replace" >
<Argument id="source" type="string" status="ByVal"/>
<Argument id="oldStr" type="integer" status="ByVal"/>
<Argument id="newStr" type="integer" status="ByVal"/>
</Method>
Its parameters are:
Parameter | Description |
source | contains the original string to be modified. |
oldStr | contains the substring whose occurrences are to be replaced. |
newStr | contains the replacing substring. |
The method returns the new string. The code below shows examples of this.
void TestReplace
{
string input;
string result;
Write.Line "Unit test for Character.Replace() Method"
input = "\Manual\FmStocks\WebSite\t_begin_cart.asp";
result = Character.Replace(input,"\","_");
Write.Line("Input<" + input + "> result<" + result + ">");
input = "some sort of text/string right here";
result = Character.Replace(input,"right","in");
Write.Line("Input<" + input + "> result<" + result + ">");
input = "Mary had a little lamb.";
result = Character.Replace(input,"lamb","tiger");
Write.Line("Input<" + input + "> result<" + result + ">");
input = "Good dog, good dog";
result = Character.Replace(input, "Good","Bad");
Write.Line("Input<" + input + "> result<" + result + ">");
}
The output of the method shows both the input string and the result string.
Unit test for Character.Replace() Method
Input<\Manual\FmStocks\WebSite\t_begin_cart.asp> result<_Manual_FmStocks_WebSite_t_begin_cart.asp>
Input<some sort of text/string right here> result<some sort of text/string in here>
Input<Mary had a little lamb.> result<Mary had a little tiger.>
Input<Good dog, good dog> result<Bad dog, Bad dog>
Character.Substr Method
The
Substr method forms a new string by extracting a substring from a supplied one.
<Method id="Substr" type="string" opcode="SCM.Character_Substr" >
<Argument id="strValue" type="string" status="ByVal"/>
<Argument id="iStart" type="integer" status="ByVal"/>
<Argument id="length" type="integer" status="ByVal"/>
</Method>
Its parameters are:
Parameter | Description |
strValue | is the supplied source string. |
iStart | is the starting offset in the source string, relative to zero, of the start of the substring. |
length | is the desired length of the substring. If it is negative or zero, then it is added to the length of the source string to determine its final value. |
The method returns the new string. The following code shows how the method is used to extract the actual reference files from a project file.
void TestSubstr()
{
int vbpRoot;
tInfoFile vbpInfo;
Handle textStream;
int rai;
int length;
string record;
int nRecord;
int curRecord;
int nString;
string refName;
Write.Line "Unit test for Character.Substr() Method"
Store.Open("\Manual\FmStocks\usr\FmStocks.vbi",StorageUnit.USER,0);
vbpRoot = Store.FindVector("\Manual\FmStocks\src\FMStocks_DB.vbp",0);
vbpInfo = Store.GetVector(vbpRoot);
textStream = Text.Open(Store.GetHandle(),vbpInfo.textBase);
nRecord = Text.Maximum(textStream);
curRecord = 0;
while(curRecord < nRecord)
{
curRecord = curRecord + 1;
Text.Position(textStream,curRecord);
record = Text.Access(textStream, length, rai, 0);
if(length > 12)
{
if(Character.Compare(record,"Reference=",10) == 0)
{
nString = length - 10;
refName = Character.Substr(record,10,nString);
Write.Line("Found Reference: " + refName);
}
}
}
Store.Close();
}
The actual reference names found are as follows
Unit test for Character.Substr() Method
Found Reference: *\G{00020430-0000-0000-C000-000000000046}#2.0#0#..\..\..\..\..\WINDOWS\system32\stdole2.tlb#OLE Automation
Found Reference: *\G{00000205-0000-0010-8000-00AA006D2EA4}#2.5#0#..\..\..\..\..\Program Files\Common Files\system\ado\msado25.tlb#Microsoft ActiveX Data Objects 2.5 Library
Found Reference: *\G{2A005C00-A5DE-11CF-9E66-00AA00A3F464}#1.0#0#..\..\..\..\..\WINDOWS\system32\COMSVCS.DLL#COM+ Services Type Library
Character.ToLower Method
The
ToLower method forces the case of any alphabetic characters contained in a specified string to lower-case. Characters that are not alphabetic or that already have lower-case are not changed.
<Method id="ToLower" type="string" opcode="SCM.Character_Tolower" >
<Argument id="strValue" type="string" status="ByVal"/>
<Argument id="iStart" type="integer" status="ByVal"/>
<Argument id="length" type="integer" status="ByVal"/>
</Method>
Its parameters are:
Parameter | Description |
strValue | is the string containing the value to be converted. |
iStart | is the starting relative to zero of the characters to be converted. |
length | is the number of characters to be considered for conversion. |
The code below shows this.
void TestTolower()
{
string input;
string output;
Write.Line "Unit test for Character.Tolower() Method"
input = "abcdefg"
output = Character.Toupper(input,0,2);
Write.Line("toupper(""" + input + """,0,2) = " + output)
input = Character.Tolower(output,1,1)
Write.Line("tolower(""" + output + """,1,1) = " + input)
}
The first call sets the first two characters to upper case and then the second call sets the second character back to lower case.
Unit test for Character.Tolower() Method
toupper("abcdefg",0,2) = ABcdefg
tolower("ABcdefg",1,1) = Abcdefg
Character.ToUpper Method
The
ToUpper method forces the case of any alphabetic characters contained in a specified string to upper-case. Characters that are not alphabetic or that already have upper-case are not changed.
<Method id="ToUpper" type="string" opcode="SCM.Character_Toupper" >
<Argument id="strValue" type="string" status="ByVal"/>
<Argument id="iStart" type="integer" status="ByVal"/>
<Argument id="length" type="integer" status="ByVal"/>
</Method>
Its parameters are:
Parameter | Description |
strValue | is the string containing the value to be converted. |
iStart | is the starting relative to zero of the characters to be converted. |
length | is the number of characters to be considered for conversion. |
The code below shows this.
void TestToupper()
{
string input;
string output;
Write.Line "Unit test for Character.Toupper() Method"
input = "abcdefg"
output = Character.Toupper(input,0,2);
Write.Line("toupper(""" + input + """,0,2) = " + output)
input = Character.Tolower(output,1,1)
Write.Line("tolower(""" + output + """,1,1) = " + input)
}
The first call sets the first two characters to upper case and then the second call sets the second character back to lower case.
Unit test for Character.Toupper() Method
toupper("abcdefg",0,2) = ABcdefg
tolower("ABcdefg",1,1) = Abcdefg
Character.Unpack Method
The
Unpack method extracts a specified string from a set of strings packed into a single string instance.
<Method id="Unpack" type="string" opcode="SCM.Character_Unpack" >
<Argument id="strValue" type="string" status="ByVal"/>
<Argument id="iStart" type="integer" status="ByVal"/>
</Method>
Its parameters are:
Parameter | Description |
strValue | contains the packed set of strings. |
iStart | is the index relative to one of the desired string. |
The method returns the unpacked string. One of the packed string sets used by
gmBasic contains the handler and argument class names for an event. The code here extracts these for the individual events in the
ADODB.ConnectionEvents class.
void TestUnpack()
{
int classRoot;
int compRoot;
tLibComp libComp;
int evtType;
string evtInfo;
Write.Line "Unit test for Character.Unpack() Method"
Store.Open("\Manual\FmStocks\usr\FmStocks.vbi",StorageUnit.USER,0);
classRoot = Symbol.FindIdentifier("ADODB.ConnectionEvents" ,0);
for(compRoot = Store.GetFirst(classRoot); compRoot != 0; compRoot = Store.GetNext(compRoot))
{
libComp = Store.GetVector(compRoot);
if(libComp.refType == ComponentType.EVENT)
{
evtType = libComp.type;
if(evtType > Defines.OPC_MAXIMUM)
{
evtInfo = Store.GetString(evtType);
Write.Line("Event components for:" + Store.GetName(compRoot));
Write.Line(" Handler:" + Character.Unpack(evtInfo,0));
Write.Line(" Args:" + Character.Unpack(evtInfo,1));
}
}
}
Store.Close();
}
The result of the scan and unpacking is shown below.
Unit test for Character.Unpack() Method
Event components for:InfoMessage
Handler:ADODB.ConnectionEvents_InfoMessageEventHandler
Args:ADODB.ConnectionEvents_InfoMessageEvent
Event components for:BeginTransComplete
Handler:ADODB.ConnectionEvents_BeginTransCompleteEventHandler
Args:ADODB.ConnectionEvents_BeginTransCompleteEvent
Event components for:CommitTransComplete
Handler:ADODB.ConnectionEvents_CommitTransCompleteEventHandler
Args:ADODB.ConnectionEvents_CommitTransCompleteEvent
Event components for:RollbackTransComplete
Handler:ADODB.ConnectionEvents_RollbackTransCompleteEventHandler
Args:ADODB.ConnectionEvents_RollbackTransCompleteEvent
Event components for:WillExecute
Handler:ADODB.ConnectionEvents_WillExecuteEventHandler
Args:ADODB.ConnectionEvents_WillExecuteEvent
Event components for:ExecuteComplete
Handler:ADODB.ConnectionEvents_ExecuteCompleteEventHandler
Args:ADODB.ConnectionEvents_ExecuteCompleteEvent
Event components for:WillConnect
Handler:ADODB.ConnectionEvents_WillConnectEventHandler
Args:ADODB.ConnectionEvents_WillConnectEvent
Event components for:ConnectComplete
Handler:ADODB.ConnectionEvents_ConnectCompleteEventHandler
Args:ADODB.ConnectionEvents_ConnectCompleteEvent
Event components for:Disconnect
Handler:ADODB.ConnectionEvents_DisconnectEventHandler
Args:ADODB.ConnectionEvents_DisconnectEvent