I saw in a screencast a while ago (since forgotten which, probably a Kata) where a person was writing out a unit test but wrote something like this:
public "return zero for an all gutter game"
Then they magically turned it into
public returnZeroForAnAllGutterGame
Is there a plugin for this or just a simple way to do a template that gets fired off on a key stroke?
I googled around and just couldn't think of a good way to type in a search to get what I wanted.
I couldn't find the plugin or macro you refer to, but I did create a macro that will work nicely!
First, to install do the following:
Press Alt+F11
Expand MyMacros
Open the EnvironmentEvents module
Past the code into the module (code is found at the end of this post)
Close the macro editor
To use the macro:
Press ` (grave key).
Next press "
Type the words you desire
End by typing "`
Watch the magic happen!
NOTE: You could just start typing a sting value then latter add the grave symbols before and after and it will still work.
The macro will remove spaces and then PascalCase the entire set of words. It also strips out single and double quotes. Lastly, it will convert commas to underscores if you want to use the naming convention suggested by Roy Osherove (The Art of Unit Testing, p. 211):
MethodUnderTest_Scenario_Behavior()
Examples:
public void `"return zero for an all gutter game"`
public void `"LoadMainParts, when materials files are valid, will return a list of parts sorted by sequential item number ascending"`
...will turn into this (after the second ` press):
public void ReturnZeroForAnAllGutterGame
public void LoadMainParts_WhenMaterialsFilesAreValid_WillReturnAListOfPartsSortedBySequentialItemNumberAscending
The Macro:
...
Imports System.Text.RegularExpressions
...
Private isPascalCaseAndSpaceRemovalEnabled As Boolean
Private Function ConvertToPascalCase(ByVal value As String) As String
'apply ToUpper on letters preceeded by a space, double quotes, or a comma'
Dim pattern As String = "[ ,"",\,][a-z]"
value = Regex.Replace(value, _
pattern, _
Function(m) m.Value.ToUpper, _
RegexOptions.Singleline)
'replace commas with underscores'
value = value.Replace(",", "_")
'remove spaces, graves, double quotes, and single qoutes'
Dim removalCharacters As String() = {" ", "`", """", "'"}
For Each character In removalCharacters
value = value.Replace(character, "")
Next
Return value
End Function
Private Sub TextDocumentKeyPressEvents_AfterKeyPress(ByVal Keypress As String, _
ByVal Selection As EnvDTE.TextSelection, _
ByVal InStatementCompletion As Boolean) _
Handles TextDocumentKeyPressEvents.AfterKeyPress
If isPascalCaseAndSpaceRemovalEnabled AndAlso Keypress = "`" Then
Selection.SelectLine()
Dim pattern As String = "`""(.*)""`"
Dim substringToReplace As String = Regex.Match(Selection.Text, _
pattern, _
RegexOptions.Singleline).Value
Selection.ReplacePattern(pattern, _
ConvertToPascalCase(substringToReplace), _
vsFindOptions.vsFindOptionsRegularExpression)
Selection.MoveToPoint(Selection.BottomPoint)
isPascalCaseAndSpaceRemovalEnabled = False
CancelKeyPress = True
ElseIf Keypress = "`" Then
isPascalCaseAndSpaceRemovalEnabled = True
End If
End Sub
Feel free to tailor the code to your needs.
Related
In VB6 VarPtr should return the address of the variable, in this case the address of the variable str which is allocated on stack, and holds a pointer to a string in memory. StrPtr (or StrPtr) should return the address of the allocated string in the memory. ByVal should just create a copy, but in this case, it works strangely:
Dim str As String
str = "asd"
Debug.Print VarPtr(str)
Debug.Print VarPtr(ByVal str)
Debug.Print StrPtr(str)
The result is:
1636452
110882980
110882980
Why is the result of VarPtr(ByVal str) the same as StrPtr(str) ?
Strings passed ByVal pass the address of the first character of the containing C string in the BStr. StrPtr does the same.
There are two reasons that spring to mind for doing this. Passing Unicode to API calls and string building.
Passing Unicode to API calls
You could use StrPtr on a string rather than a byte array when sending Unicode strings to API functions.
Dim ByteArr() as Byte
Var1="My Text"
ByteArr = Var1
APICall(ByteArr(0))
APICall(StrPtr(Var1))
Should both pass a Unicode string to an API functions. Unicode strings are converted to ANSI strings when using the declare statement as Win 95 didn't do unicode.
String Building
On the other hand if you are string building, then that is built in to VBA using the Left, Right, and Mid statements, not functions (they are overloaded).
Sub Main()
Dim Var As String
Var = "gggggggggggg"
MsgBox StrPtr(Var)
Mid(Var, 1, 2) = "xx"
MsgBox StrPtr(Var) & " - " & Var
End Sub
ByVal Versus ByRef
Some authors like to say that the ByVal keyword is overloaded for
strings, meaning that it takes on a different meaning when applied to
strings than when applied to other variables. Frankly, I don't see it.
Writing:
ByVal str As String
tells VB to pass the contents of the BSTR (actually the ABSTR), which is the pointer to the character array. Thus, ByVal is acting
normally--it just happens that the content of the BSTR is a pointer to
another object, so this simulates a pass by reference. Similarly:
ByRef str As String
passes the address of the BSTR, as expected.
Win32 API Programming with Visual Basic, Chapter 6 Strings, O'Reilly, from MSDN Library October 2001
StrPtr
Strings in Visual Basic are stored as BSTR's. If you use the VarPtr on
a variable of type String, you will get the address of the BSTR, which
is a pointer to a pointer of the string. To get the address of the
string buffer itself, you need to use the StrPtr function. This
function returns the address of the first character of the string.
Take into account that Strings are stored as UNICODE in Visual Basic.
To get the address of the first character of a String, pass the String
variable to the StrPtr function.
Example:
Dim lngCharAddress as Long
Dim strMyVariable as String
strMyVariable = "Some String"
lngCharAddress = StrPtr(strMyVariable)
You can use this function when you need to pass a pointer to a
UNIOCODE string to an API call.
HOWTO: Get the Address of Variables in Visual Basic Q199824 Microsoft Knowledge Base, MSDN October 2001.
VarPtr is not part of the VBA/VB6 language, therefore companies that implement VBA (like Corel) may not implement it in their VBA. The VBA spec is here https://msdn.microsoft.com/en-us/library/dd361851.aspx
We have noticed that sometimes from the results of an AJAX call to a controller action that the case of the JSON result is incorrect. The returned case will actually change if we rebuild our solution and try the exact same call. In the following case, the key's case has been correct for over a year until now when it has decided to start randomly changing depending on some seemingly random circumstances.
As you can see in the picture above, the key for the JSON result is lowercase "success". However when I view the results in Chrome's console, it is an uppercase "Success". This is causing our JavaScript to fail since it is checking for the lowercase version.
What is causing this? And more importantly, how do we stop this?
vb.net is case-insensitive as opposed to C# which is case-sensitive. This means that the compiler will generate only one class (from the first instance) for each of the following anonymous types:
Dim a = New With {.success = True} 'Compiler generate a class based on this type
Dim b = New With {.Success = True} 'Same type as `a`
Dim c = New With {.sUcCeSs = True} 'Same type as `a`
Debug.WriteLine(a.GetType().Name)
Debug.WriteLine(b.GetType().Name)
Debug.WriteLine(c.GetType().Name)
VB$AnonymousType_0'1
VB$AnonymousType_0'1
VB$AnonymousType_0'1
Here's how the complied code looks like when compiled back to vb.net:
<DebuggerDisplay("success={success}"), CompilerGenerated> _
Friend NotInheritable Class VB$AnonymousType_0(Of T0)
' Methods
<DebuggerNonUserCode> _
Public Sub New(ByVal success As T0)
Me.$success = success
End Sub
<DebuggerNonUserCode> _
Public Overrides Function ToString() As String
Dim builder As New StringBuilder
builder.Append("{ ")
builder.AppendFormat("{0} = {1} ", "success", Me.$success)
builder.Append("}")
Return builder.ToString
End Function
Public Property success As T0
<DebuggerNonUserCode> _
Get
Return Me.$success
End Get
<DebuggerNonUserCode> _
Set(ByVal Value As T0)
Me.$success = Value
End Set
End Property
Private $success As T0
End Class
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 8 years ago.
Improve this question
I want to make a search tool to find a specific word in the Arabic language that i can find just the word for example:
ذهب الولد إلى المدرسة من البيت و منهم الى البيت
If I try to find the word "من", the code not only finds the word "من", but also finds part of the word " منهم". I don't want the program to do that. I want to find the word " من" and every word like it and make whole case to the word.
To make things more clear (using an English example), if I were to search for the word 'to' in the following sentence, I would only want whole words to be found, and not words that contain the word 'to' such as 'toward' to become a part of the result.
Sentence: I want to go towards the bus.
Searches like this can be frustrating. What I usually do is to add a space at the front of the search string and also at the end and then search for SearchString.
So... "I want to go towards the bus." becomes " I want to go towards the bus. ". Then I search for " to ". The problem with this method is that punctuation can cause a problem. For example, if you wanted to search for "bus", you would use:
" I want to go towards the bus. " and search for " bus ". This would not be found because there is punctuation after the word bus.
I would encourage you to use regular expressions for this functionality. VB6 does not have regular expressions built in, but you can use the Microsoft VBScript Regular Expressions functionality to accomplish this. Please take a look at this page to help you get started: http://support.microsoft.com/kb/818802
Edit based on your comment
You have this line of code:
pos = InStr(start_at, txtBody.Text, target)
try changing that line to this:
pos = InStr(start_at, " " & txtBody.Text & " ", " " & target & " ", vbBinaryCompare)
By adding spaces in the code, you are actually checking for (space)target(space). So that you don't miss potential matches at the beginning or end of txtBody.Text, spaces are added there (for comparison purposes only). By adding vbBinaryCompare, InStr will now perform a case sensitive search.
The only completely thorough way of doing this is to use the Instr() function, and then check that the next character is a punctuation character, a newline, or the word is at the end of the string, e.g.
Option Explicit
Private Declare Function GetStringTypeW Lib "Kernel32.dll" ( _
ByVal dwInfoType As Long, _
ByVal lpSrcStr As Long, _
ByVal cchSrc As Long, _
ByRef lpCharType As Integer _
) As Long
Private Const CT_CTYPE1 As Long = &H1
Private Const C1_UPPER As Long = &H1 ' Uppercase
Private Const C1_LOWER As Long = &H2 ' Lowercase
Private Const C1_DIGIT As Long = &H4 ' Decimal digits
Private Const C1_SPACE As Long = &H8 ' Space characters
Private Const C1_PUNCT As Long = &H10 ' Punctuation
Private Const C1_CNTRL As Long = &H20 ' Control characters
Private Const C1_BLANK As Long = &H40 ' Blank characters
Private Const C1_XDIGIT As Long = &H80 ' Hexadecimal digits
Private Const C1_ALPHA As Long = &H100 ' Any linguistic character: alphabetical, syllabary, or ideographic
Private Const C1_DEFINED As Long = &H200 ' A defined character, but not one of the other C1_* types
Function FindFullWord(ByVal in_lStartPos As Long, ByRef in_sText As String, ByRef in_sSearch As String, Optional ByVal in_eCompareMethod As VbCompareMethod = vbBinaryCompare) As Long
Dim nLenText As Long
Dim nLenSearch As Long
Dim sNextChar As String
Dim iCharType As Integer
FindFullWord = InStr(in_lStartPos, in_sText, in_sSearch, in_eCompareMethod)
' Did we find the search string in the text?
If (FindFullWord > 0) Then
' Save the length of the text.
nLenText = Len(in_sText)
nLenSearch = Len(in_sSearch)
Do
' Does this position mean that the search is the end of the string?
If (FindFullWord + nLenSearch - 1) = nLenText Then
' If so, we can exit now - there are no following characters.
Exit Function
End If
' Look at the next character.
sNextChar = Mid$(in_sText, FindFullWord + nLenSearch, 1)
' Is this next char a space, punctuation character, or a blank?
If (GetStringTypeW(CT_CTYPE1, StrPtr(sNextChar), 1, iCharType)) Then
If (iCharType And C1_SPACE) = C1_SPACE Then
Exit Function
ElseIf (iCharType And C1_PUNCT) = C1_PUNCT Then
Exit Function
ElseIf (iCharType And C1_BLANK) = C1_BLANK Then
Exit Function
End If
End If
' Find the position of the search string in the text.
FindFullWord = InStr(FindFullWord + nLenSearch, in_sText, in_sSearch, in_eCompareMethod)
Loop Until FindFullWord = 0
End If
End Function
I originally started doing a test for every character which could follow a word and would not be part of that word, but the code started getting very long. And, of course, I know absolutely nothing about Arabic. So I wondered whether there was a standard way of finding out the general "type" of a character, regardless of language. And as it happens, there was.
The GetStringTypeW() method is documented in the Win32 documentation, and essentially can retrieve information about all the characters in a string. In my case, I am only looking at the character which follows the search word in a piece of text. The variable iCharType which returns the value from the string is a bitfield, and contains a number of values OR'ed together. I am using the AND operator to isolate just the values I am interested in.
I am a long time C# developer and have had to look at some VB6 code lately. After some digging, we found out that, somewhere, somehow, we are storing a number as a string. Now we are reading it back and our code is not handling culture differences very well. Here is an example:
Dim text as String
Dim myVal as Double
Set text = "1,123456"
'This sets the value of myVal to 1123456 on our system - incorrect
myVal = text
Set text = "1.123456"
'This sets the value of myVal to 1.123456 on our system - correct
myVal = text
Keeping in mind that this is VB6 and NOT VB.NET, are there any built-in methods, functions, whatever, that can convert a string to a double using a particular culture?
Or at the very least, hinting to the conversion that we may be dealing with a different format?
We are still digging how the value gets written and see if we can reverse engineer the process to give us a consistent result. However, our customer(s) already has(have) data in one format or the other (or both, we are checking...), so a proper conversion algorithm or implementation would be a better answer at this point.
I've used this quick and dirty function in the past to get a double from a text. Here in Argentina, people sometimes use the point and sometimes the comma to separate decimal values, so this function is ready to accept both formats. If only one punctuation is present, it's assumed that it's the decimal separator.
function ConvertDBL( texto )
dim retval, SepDecimal, SepMiles
If texto = "" then texto = "0"
retval = replace(trim(texto), " ", "")
If cdbl("3,24") = 324 then
SepDecimal = "."
SepMiles = ","
else
SepDecimal = ","
SepMiles = "."
end if
If InStr( Retval, SepDecimal ) > 0 then
If InStr( Retval, SepMiles ) > 0 then
If InStr( Retval, SepDecimal ) > InStr( Retval, SepMiles ) then
Retval = replace( Retval, SepMiles, "" )
else
Retval = replace( Retval, SepDecimal, "" )
Retval = replace( Retval, SepMiles, SepDecimal )
end if
end if
else
Retval = replace( Retval, SepMiles, SepDecimal )
end if
ConvertDbl = cdbl( retval )
end function
You cannot choose an arbitrary culture by passing a culture object like you can in .Net. You can choose:
Functions which always use the current regional settings. CStr, Format, CDbl etc. Implicit conversions (like the ones in your question) also use the current regional settings.
Functions which always use USA regional settings (similar to the .Net invariant culture). Str, Val
Usually the current regional settings are taken from Control Panel. There are rumours that you can call SetThreadLocale to change the regional settings from code at runtime - never tried it myself.
In Visual Basic tested works very fast and efficient.
Step 1: Conversion from a string to a value representation.
Step 2: Conversion from a value representation to a double integer value.
Dim Str as String
Dim mValue as double
str = "100,10"
mValue = CDbl(Val(str))
Need a function that takes a character as a parameter and returns true if it is a letter.
This was part of the code posted by rpetrich in response to a question by Joel Spolsky. I felt it needed a post specific to the problem it solves. It really is brilliant.
Private Function IsLetter(ByVal character As String) As Boolean
IsLetter = UCase$(character) <> LCase$(character)
End Function
You may be thinking to yourself, "Will this always work?" The documentation on the UCase and LCase functions, confirms that it will:
UCase Function Only lowercase letters are converted to uppercase;
all uppercase letters and nonletter characters remain unchanged.
LCase Function Only uppercase letters are converted to lowercase;
all lowercase letters and nonletter characters remain unchanged.
Seanyboy's IsCharAlphaA answer is close. The best method is to use the W version like so:
Private Declare Function IsCharAlphaW Lib "user32" (ByVal cChar As Integer) As Long
Public Property Get IsLetter(character As String) As Boolean
IsLetter = IsCharAlphaW(AscW(character))
End Property
Of course, this all rarely matters as all of VB6's controls are ANSI only
Private Function IsLetter(Char As String) As Boolean
IsLetter = UCase(Char) Like "[ABCDEFGHIJKLMNOPQRSTUVWXYZ]"
End Function
What's wrong with the following, which doesn't rely on obscure language behaviour?
Private Function IsLetter(ByVal ch As String) As Boolean
IsLetter = (ch >= "A" and ch <= "Z") or (ch >= "a" and ch <= "z")
End Function
I believe we can improve upon this a little more. rpetrich's code will work, but perhaps only by luck. The API call's parameter should be a TCHAR (WCHAR here actually) and not a Long. This also means no fiddling with converting to a Long or masking with &HFFFF. This by the way is Integer and adds an implicit conversion to Long here too. Perhaps he meant &HFFFF& in this case?
On top of that it might be best to explictly call the UnicoWS wrapper for this API call, for Win9X compatibility. The UnicoWS.dll may need to be deployed but at least we gain that option. Then again maybe from VB6 this is automagically redirected, I don't have Win9X installed to test it.
Option Explicit
Private Declare Function IsCharAlphaW Lib "unicows" (ByVal WChar As Integer) As Long
Private Function IsLetter(Character As String) As Boolean
IsLetter = IsCharAlphaW(AscW(Character))
End Function
Private Sub Main()
MsgBox IsLetter("^")
MsgBox IsLetter("A")
MsgBox IsLetter(ChrW$(&H34F))
MsgBox IsLetter(ChrW$(&HFEF0))
MsgBox IsLetter(ChrW$(&HFEFC))
End Sub
Looking around a bit came up with the following...
Private Declare Function IsCharAlphaA Lib "user32" Alias "IsCharAlphaA" (ByVal cChar As Byte) As Long
I believe IsCharAlphaA tests ANSI character sets and IsCharAlpha tests ASCII. I may be wrong.
Private Function IsAlpha(ByVal vChar As String) As Boolean
Const letters$ = "abcdefghijklmnopqrstuvwxyz"
If InStr(1, letters, LCase$(vChar)) > 0 Then IsAlpha = True
End Function
I use this in VBA
Function IsLettersOnly(Value As String) As Boolean
IsLettersOnly = Len(Value) > 0 And Not UCase(Value) Like "*[!A-Z]*"
End Function
It doesn't exactly document itself. And it may be slow. It's a clever hack, but that's all it is. I'd be tempted to be more obvious in my checking. Either use regex's or write a more obvious test.
public bool IsAlpha(String strToCheck)
{
Regex objAlphaPattern=new Regex("[^a-zA-Z]");
return !objAlphaPattern.IsMatch(strToCheck);
}
public bool IsCharAlpha(char chToCheck)
{
return ((chToCheck=>'a') and (chToCheck<='z')) or ((chToCheck=>'A') and (chToCheck<='Z'))
}