VB / VBA StrComp or = - excel

What, if anything, is the benefit of using
If StrComp(strVal1, strVal2, vbTextCompare) = 0 Then
as opposed to using
If strVal1 = strVal2 Then
If Option Compare Text is set at the module level, is there any difference?
I know StrComp handles null scenarios and <> scenarios, I am only interested in the situation where strVal1 and strVal2 have non-null valid strings assigned.

If Option Compare Text is set at the module level, is there any difference?
No. It simply offers a finer grained control (no module-level strategy commitments). However, if you can make such a commitment, go for the x = y option: less code is always better code.

Since StrComp is comparing string (with cultural info), UpperCase and LowerCase are not taking care ... (so Hello is the same as hello). In the case of =, there will be different (Like using a Binary compare).
If option compare text is at module level, there will be no difference (but you should use StrComp in case another guy delete it)...

Related

Can I define a constant in VBA to be used in Excel worksheet?

Instead of using the same defined name in multiple workbooks, can I define a constant in my xlam file that can then be used in all my workbooks?
For example, in VBA:
Public Const nKilobyte = 1024
Then in a worksheet:
=A1 / nKilobyte
I tried this and I get a #NAME? error. Right now, it looks like a worksheet can refer to functions defined in VBA, but not constants. So as a workaround, I made up the following function:
Public Function vConstant(sName As String) As Variant
Select Case sName
Case "kb": vConstant = 1024
Case "Mb": vConstant = 1024 ^ 2
End Select
End Function
which I can then call in a worksheet as:
=A1 / vConstant("kb")
That works, but an actual constant would be better. Is there a way to do that?
That works, but an actual constant would be better. Is there a way to do that?
Nope.
Excel and VBA are two separate things: they talk to each other using a predefined pipeline, and that interface says public procedures in standard modules are exposed as "macros", and public functions in standard modules are exposed as user-defined functions. In the other direction, VBA gets to talk to Excel through its object model.
The Excel calc engine knows nothing of the VBA runtime context that's holding the runtime values of your global variables and constants: that's purely on the VBA side of things. In fact, it wouldn't be unreasonable to assume a constant doesn't even exist in the compiled code - that's actually the case in C# code: the compiler "burns" the value of constants in-place, at the call sites. I wouldn't be surprised to crack open the compiled p-code and find that all constants are just inlined into their call sites... but that's all just speculation.
For whatever it's worth, that magic-string driven function isn't ideal; callers might end up scratching their heads wondering whether it wants "KB", "Kb", "kB" or "kb" (Option Compare Binary being the default string comparison mechanism in VBA, i.e. case-sensitive), or maybe it was "KiB"? Make sure the supported values are well-documented, and use StrComp with text rather than binary comparison to make the match case-insensitive.
Consider exposing a single function / UDF per constant. That'll eliminate the magic strings and enhance the UDF usability.
Public Function BytesInKB() As Long
BytesInKB = CLng(1024)
End Function
Public Function BytesInMB() As Long
BytesInMB = CLng(1024) ^ 2
End Function

How can I say that all elements in an array must have some property in OCL?

I have the following class:
and I would like to express in OCL the following constraint:
Every String in pre must either contain ('not' and one ' ') or contain no ' '
is it possible? How can I write it?
Thank you!!
P.s. By writing ' ' I mean a whitespace.
You've done a fairly good job of using formal English so transliteration to OCL is now easy. But you have used List<> which is not a UML or OCL facility, so without providing its operations who knows? I therefore assume you use some form of Collection, possibly Sequence. (In UML you get Collections automnatically by specifying an uopper bound greater than 1.)
Ideally you could transliterate to:
pre->forAll(s |
(s.contains('not') and (s.count(' ') = 1)) or (s.count(' ') = 0))
but standard OCL has no String::contains() or String:::count() so we'll have to work a bit harder. Eclipse OCL has String::tokenize(), String:lastIndexOf() and String::matches() any of which could be used. But in Standard OCL, we probably have to resort to characters() to create a Sequence of String each containing one character.
For s.contains('not') use s.indexOf('not') >= 0
For s.count(' ') use s.characters->count(' ')
and to avoid evaluating s.characters->count(' ') twice on a poor OCL tool, introduce a let variable.

How to represent a missing xsd:dateTime in RDF?

I have a dataset with data collected from a form that contains various date and value fields. Not all fields are mandatory so blanks are possible and
in many cases expected, like a DeathDate field for a patient who is still alive.
How do I best represent these blanks in the data?
I represent DeathDate using xsd:dateTime. Blanks or empty spaces are not allowed. All of these are flagged as invalid when validating using Jena RIOT:
foo:DeathDate_1
a foo:Deathdate ;
time:inXSDDatetime " "^^xsd:dateTime .
foo:DeathDate_2
a foo:Deathdate ;
time:inXSDDatetime ""^^xsd:dateTime .
foo:DeathDate_3
a foo:Deathdate ;
time:inXSDDatetime "--"^^xsd:dateTime .
I prefer to not omit the triple because I need to know if it was blank on the source versus a conversion error during construction of my RDF.
What is the best way to code these missing values?
You should represent this by just omitting the triple. That's the meaning of a triple that's "not present": it's information that is (currently) unknown.
Alternatively, you can choose to give it the value "unknown"^^xsd:string when there's no death date. The solution in this case is to not datatype it as an xsd:dateTime, but just as a simple string. It doesn't have to be a string of course, you could use any kind of "special" value for this, e.g. a boolean false - just as long as it's a valid literal value that you can distinguish from actual death dates. This will solve the parsing problem, but IMHO if you do this, you are setting yourself up for headaches in processing the data further down the line (because you will need to ask queries over this data, and they will have to take two different types of values into account, plus the possibility that the field is missing).
I prefer to not omit the triple because I need to know if it was blank
on the source versus a conversion error during construction of my RDF.
This sounds like an XY problem. If there are conversion errors, your application should signal that in another way, e.g. by logging an error. You shouldn't try to solve this by "corrupting" your data.

Making sure string numbers operations are culture independent

I download an exchange rate through an XmlHttp request that gets inside the code as a string (being the .innerText of a <div> element) and represents a double type number: 1.525.
When building this script, I've done it on my OS which has the English culture model (i.e. 1.525 means 1 unit and 0.525 decimals).
However, this script will now run on a French OS which uses the comma , instead of the . to separate decimals.
Which means, the operation Application.Evaluate(10000/myRate) will fail if the . is instead of the ,.
Easy solution would be to replace the "." with a "," via Application.Evaluate(10000/Replace(myRate,".",","). However, this is clearly not nice because now the script would fail on an English system.
With VB.NET I would be able to make it culture-independent by converting it like:
myRate.ToDouble(System.Globalization.CultureInfo.InvariantCulture)
I've tried Googling the VBA alternative for a while without success; does anyone know if there's a more elegant way of internationalize my script than just replacing the "." with a ","?
Here's my current solution (that I don't really like):
On Error Resume Next
test = CDbl(myRate)/2
If Err.Number <> 0 Then
myRate = Replace(myRate,".",",")
On Error GoTo 0
End If
use the Application.DecimalSeparator property?
Application.Evaluate(10000/CDbl(Replace(myRate,".", Application.DecimalSeparator))
You can temporary change decimal and thousands separator, by using Application object.
To read several current OS (International) settings: Application.International(index) property
To change:
Application.ThousandsSeparator = "."
In MS Access, we do not have Application.DecimalSeparator nor Application.ThousandsSeparator nor Application.International. The only thing we have is Val(vString) and Str(vNumber). They both convert the argument using the English (invariant) culture.
So, in MS Access the OP's question could be solved like this:
vResult = 10000/Val(myRate)

Is VB6 string comparison case insensitive?

if strValue = 'Hello' then what would be the value of (strValue <> 'HELLO') be?
It depends on how you use the Option Compare statement. It can work either way.
Option Compare Text 'Case insensitive'
Option Compare Binary 'Case sensitive (default)'
Here's a VB6 string tutorial.
No, it's case sensitive (by default at least though you'll want to check - if Option Compare is set to Binary or not set then it's case sensitive, if it's set to text then it's case insensitive).
Lcase() both sides if you'd rather it were case insensitive.
The reason I prefer this to changing / setting option compare is that someone looking at the code doesn't have to go hunting to see what option compare is set to to understand how it's going to behave BUT it's almost certainly slower (not significantly unless you're calling it repeatedly) and some might see it as not particularly neat.
The documentation is fairly clear
If you use Option Compare Text in the Declarations section of a
module [the top of the file], string comparisons aren't case-sensitive.
If you use Option Compare Binary, comparisons are case-sensitive.
If you use Option Compare Database [only valid in Access VBA], the comparison method is set by the current database.

Resources