Hello everyone.
Dim txt1 As Double = Convert.ToDouble(TextBox1.Text) / 100
Dim txt2 As Double = Convert.ToDouble(TextBox2.Text)
Dim txt3 As Double = Convert.ToDouble(TextBox3.Text)
Dim txtResult As Double = Convert.ToDouble(TextBox4.Text)
Dim result As Double = txt1 * txt2 * txt3
TextBox4.Text = result
As you can see I get my result depending on what the user types in. So I have to add a space after a certain character. Textbox14.text(0) <--- after this do I want my space. It's so that after the value is higher than 999 it should type out 1 000 and not 1000. Thank you very much for any useful help, I've truly looked everywhere, I just can't find anything.
You talking about group separator. Custom Numeric Format Strings
You can use .ToString() method and define group separator in the format.
TextBox4.Text = result.ToString("0,0.000")
Different separators will be used based on the local system's language/region settings.
You can define your custome separator manually
var cultureInfo = new System.Globalization.CultureInfo("en-US");
var numberInfo = cultureInfo.NumberFormat;
numberInfo.NumberGroupSeparator = " ";
TextBox4.Text = result.ToString("0,0.000", numberInfo)
If I get it right, you want every 3 chars a space, right ?
Like 1 000 000 ?
try this :
Dim result As String, str As String, ret As String
Dim i As Integer
Dim arr As Char()
'your text to space
result = "10000000"
'reverte so we start with the end
result = StrReverse(result)
i = 0
ret = ""
' make a char array which each char is an own array element
arr = result.Take(result.Length).ToArray
'iterate through all elements
For Each str In arr
' skip the first element .
' only add a space every 3 elements
If (i <> 0) And (i Mod 3 = 0) Then
ret = ret + " "
End If
ret = ret + str
i = i + 1
Next
' revers again the output
ret = StrReverse(ret)
MsgBox(ret)
Related
I need to remove the numeric part at the end of a string. Here are some examples:
"abcd1234" -> "abcd"
"a3bc45" -> "a3bc"
"kj3ih5" -> "kj3ih"
You get the idea.
I implemented a function which works well for this purpose.
Function VarStamm(name As String) As String
Dim i, a As Integer
a = 0
For i = Len(name) To 1 Step -1
If IsNumeric(Mid(name, i, 1)) = False Then
i = i + 1
Exit For
End If
Next i
If i <= Len(name) Then
VarStamm = name.Substring(0, i - 1)
Else
VarStamm = name
End If
End Function
The question is: is there any faster (more efficient in speed) way to do this? The problem is, I call this function within a loop with 3 million iterations and it would be nice to have it be more efficient.
I know about the String.LastIndexOf method, but I don't know how to use it when I need the index of the last connected number within a string.
You can use Array.FindLastIndex and then Substring:
Dim lastNonDigitIndex = Array.FindLastIndex(text.ToCharArray(), Function(c) Not char.IsDigit(c))
If lastNonDigitIndex >= 0
lastNonDigitIndex += 1
Dim part1 = text.Substring(0, lastNonDigitIndex)
Dim part2 = text.Substring(lastNonDigitIndex)
End If
I was skeptical that the Array.FindLastIndex method was actually faster, so I tested it myself. I borrowed the testing code posted by Amessihel, but added a third method:
Function VarStamm3(name As String) As String
Dim i As Integer
For i = name.Length - 1 To 0 Step -1
If Not Char.IsDigit(name(i)) Then
Exit For
End If
Next i
Return name.Substring(0, i + 1)
End Function
It uses your original algorithm, but just swaps out the old VB6-style string methods for newer .NET equivalent ones. Here's the results on my machine:
RunTime :
- VarStamm : 00:00:07.92
- VarStamm2 : 00:00:00.60
- VarStamm3 : 00:00:00.23
As you can see, your original algorithm was already quite well tuned. The problem wasn't the loop. The problem was Mid, IsNumeric, and Len. Since Tim's method didn't use those, it was much faster. But, if you stick with a manual for loop, it's twice as fast as using Array.FindLastIndex, all things being equal
Given your function VarStamm and Tim Schmelter's one named VarStamm2, here is a small test performance I wrote. I typed an arbitrary long String with a huge right part, and ran the functions one million times.
Module StackOverlow
Sub Main()
Dim testStr = "azekzoerjezoriezltjreoitueriou7657678678797897898997897978897898797989797"
Console.WriteLine("RunTime :" + vbNewLine +
" - VarStamm : " + getTimeSpent(AddressOf VarStamm, testStr) + vbNewLine +
" - VarStamm2 : " + getTimeSpent(AddressOf VarStamm2, testStr))
End Sub
Function getTimeSpent(f As Action(Of String), str As String) As String
Dim sw As Stopwatch = New Stopwatch()
Dim ts As TimeSpan
sw.Start()
For i = 1 To 1000000
f(str)
Next
sw.Stop()
ts = sw.Elapsed
Return String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
ts.Hours, ts.Minutes, ts.Seconds,
ts.Milliseconds / 10)
End Function
Function VarStamm(name As String) As String
Dim i, a As Integer
a = 0
For i = Len(name) To 1 Step -1
If IsNumeric(Mid(name, i, 1)) = False Then
i = i + 1
Exit For
End If
Next i
If i <= Len(name) Then
VarStamm = name.Substring(0, i - 1)
Else
VarStamm = name
End If
End Function
Function VarStamm2(name As String) As String
Dim lastNonDigitIndex = Array.FindLastIndex(name.ToCharArray(), Function(c) Not Char.IsDigit(c))
If lastNonDigitIndex >= 0 Then
lastNonDigitIndex += 1
Return name.Substring(0, lastNonDigitIndex)
End If
Return name
End Function
End Module
Here is the output I got:
RunTime :
- VarStamm : 00:00:38.33
- VarStamm2 : 00:00:02.72
So yes, you should choose his answer, his code is both pretty and efficient.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 5 years ago.
Improve this question
So, I have two strings that are each a max length of 100.
Dim a as String ''has a max length of 100
Dim b as String ''has a max length of 100
These two strings need to be truncated and combined into a new string.
Dim c as String 'has a max length of 100
I need to be able to truncate each string appropriately so that I can get string c as close to 100. I was going to do a bunch of statements by 25 to truncate each one.
if a.length = 100 and b.length =0 then
return a
else if a.length = 100 andalso b.length <= 25 then
return a.truncate(75) & b
else if a.length = 100 andalso b.length <= 50 then
return a.truncate(50) & b
else if....
and so one to hit all the scenarios...
I feel like there is a better way to do this and a more efficient way so that i may not hit scenarios like a.length = 100 and b.length = 51. I would be truncating more characters then needed.
Any suggestions?? Please critique me as needed.
EDIT, This is vb.Net..not C# (I'm between Projects) Sorry!
The reason i do not want to just add them together and truncate them is because if both strings are 100 in length, it will completely truncate off the second string. If they are both 100 then I would want to truncate string a to 50 in length and string b to 50 in length so when they are combined they are 100 total. In other words I need some text from both strings.
If the total length of the strings is greater than the limit then you could take a fraction of each in proportion to their lengths:
Module Module1
Function CombineWithLengthConstraint(a As String, b As String, totalLength As Integer) As String
' trivial case 1:
If totalLength < 1 Then
Return String.Empty
End If
Dim aLen = Len(a)
Dim bLen = Len(b)
' trivial case 2:
If aLen + bLen <= totalLength Then
Return a & b
End If
' impossible-to-satisfy-equably case:
If totalLength = 1 Then
If aLen > 0 Then
Return a.Substring(0, 1)
ElseIf bLen > 0 Then
Return b.Substring(0, 1)
Else
Return String.Empty
End If
End If
' aportion the lengths of the strings to be taken in the ratio of their lengths:
Dim aFrac = CInt(Math.Round(aLen / (aLen + bLen) * totalLength, MidpointRounding.AwayFromZero))
Dim bFrac = CInt(Math.Round(bLen / (aLen + bLen) * totalLength, MidpointRounding.AwayFromZero))
' ensure there is at least one character from each string...
If aFrac = 0 Then
aFrac = 1
bFrac -= 1
End If
If bFrac = 0 Then
bFrac = 1
aFrac -= 1
End If
Dim aPart = a.Substring(0, aFrac)
Dim bPart = b.Substring(0, bFrac)
Return aPart & bPart
End Function
Sub Main()
Dim a = New String("A"c, 10)
Dim b = New String("b"c, 40)
Dim c = CombineWithLengthConstraint(a, b, 10)
Console.WriteLine(c)
Console.WriteLine(Len(c))
Console.ReadLine()
End Sub
End Module
Outputs:
AAbbbbbbbb
10
As you can see, the first string, which was 1/5 of the total number of characters, ended up contributing 1/5 of the result.
The VB.NET Len function gives 0 if its argument is Nothing.
I tested it as working with all lengths from 0 to 100 of both strings being combined into one string of length 100 just in case I had made a mistake with the rounding or anything.
Of course, you could return, say, the ending part of string b instead of the starting part if that made sense in the particular application.
Although not exactly what you asked for, here's another option...
Public Function WeirdConcatinate(a As String, b As String) As String
Dim totalLen = a.Length + b.Length
If totalLen > 100 Then
Dim aLen = 100 * a.Length \ totalLen
Dim bLen = 100 - aLen
Return a.Remove(aLen) & b.Remove(bLen)
Else
Return a & b
End If
End Function
This will give you a number of characters from each string (approximately) proportional to how long they are compared to each other. If both strings are the same length, you'll get 50 from each. If a.Length = 100 and b.Length = 50, you'll end up with 66 from a and 34 from b.
Truncate them after concatenating them, then:
Dim c = a & b
If c.Length > 100 Then c = c.Remove(100)
If you want to preserve as much as possible of the start of each string:
Dim c = ""
If(a.Length > 50 AndAlso b.Length < 50)
c = a.Remove(100 - b.Length) & b
Else If a.Length > 50 AndAlso b.Length > 50
c= a.Remove(50) & b.Remove(50)
Else
c = a & b
End if
If c.Length > 100 Then c = c.Remove(100)
As with some other answers, the algorithm is open to interpretation. My method takes from each string until 100 total characters are taken or the string runs out of characters.
Private Function concat(a As String, b As String, length As Integer) As String
Dim ca As New System.Text.StringBuilder()
Dim cb As New System.Text.StringBuilder()
For i As Integer = 0 To length - 1
ca.Append(If(i >= a.Length, "", a(i)))
cb.Append(If(i >= b.Length, "", b(i)))
If ca.Length + cb.Length >= length Then Exit For
Next
Return (ca.ToString() & cb.ToString() & New String(" "c, 100)).Substring(0, length)
End Function
Sub Main()
Dim a As String = New String("a"c, 0)
Dim b As String = New String("b"c, 5)
Dim c As String = concat(a, b, 100)
Console.WriteLine($"'{c}'")
End Sub
'bbbbb '
(padded to 100 characters, doesn't render in block quote)
Dim a As String = New String("a"c, 30)
Dim b As String = New String("b"c, 90)
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
Dim a As String = New String("a"c, 72)
Dim b As String = New String("b"c, 64)
'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'
(your example in a comment. 72 >> 50, 64 >> 50)
As part of a larger script, I am trying to replace fraction values with decimal values in excel using vbscript. I can always count on the values to have a specific column and a specific format.
Excel example expected input column B:
51-7/16
1-1/2
2
15-7/8
Excel example desired output column B:
51.4375
1.5
2
15.875
I know it will always be to a 1/16th. So my idea was to go through the list looking for each possible fraction, find a cell that contains that fraction, and replace it with the corresponding decimal.
Questions: How do I tell the script to find a cell that contains a value and how do I replace that fraction with the decimal?
closest example Search and Replace a number of characters in Excel using VBscript
Attempt:
Dim FMember (14)
FMember(0) = "-1/16"
FMember(1) = "-1/8"
FMember(2) = "-3/16"
FMember(3) = "-1/4"
FMember(4) = "-5/16"
FMember(5) = "-3/8"
FMember(6) = "-7/16"
FMember(7) = "-1/2"
FMember(8) = "-9/16"
FMember(9) = "-5/8"
FMember(10) = "-11/16"
FMember(11) = "-3/4"
FMember(12) = "-13/16"
FMember(13) = "-7/8"
FMember(14) = "-15/16"
Dim DMember(14)
DMember(0) = ".0625"
DMember(1) = ".125"
DMember(2) = ".1875"
DMember(3) = ".25"
DMember(4) = ".3125"
DMember(5) = ".375"
DMember(6) = ".4375"
DMember(7) = ".5"
DMember(8) = ".5625"
DMember(9) = ".625"
DMember(10) = ".6875"
DMember(11) = ".75"
DMember(12) = ".8125"
DMember(13) = ".875"
DMember(14) = ".9375"
Dim endRow2
endRow2 = objSheet2.UsedRange.Rows.Count
For lngPosition = LBound(FMember) To UBound(FMember)
For r = 1 To endRow2
If objSheet2.Cells(r, objSheet2.Columns("B").Column).Value = FMember(lngPosition) Then
objSheet2.replace
End If
Next
Next
Use split()
Function fract(str As String) As Double
Dim strArr() As String
If InStr(str, "-") Then
strArr = Split(str, "-")
fract = strArr(0) + Application.Evaluate(strArr(1))
Else
fract = Application.Evaluate(str)
End If
End Function
Then you can use it as a worksheet function:
=fract(A1)
I am new to VB and I am trying to get a program to output text instead of hex. I found the code online, a program called maxiCOM. Here is the link http://www.innovatic.dk/knowledg/SerialCOM/SerialCOM.htm. The source code can be downloaded at the bottom of the page.
Unfortunately, the level of coding in the program is far above my level of understanding, and I don't really get how to change the output from hex to text. I would greatly appreciate it if someone could explain to me how to do this. The snippet of the code is
Public Class MaxiTester
Dim SpaceCount As Byte = 0
Dim LookUpTable As String = "0123456789ABCDEF"
Dim RXArray(2047) As Char ' Text buffer. Must be global to be accessible from more threads.
Dim RXCnt As Integer ' Length of text buffer. Must be global too.
' Make a new System.IO.Ports.SerialPort instance, which is able to fire events.
Dim WithEvents COMPort As New SerialPort
Private Sub Receiver(ByVal sender As Object, ByVal e As SerialDataReceivedEventArgs) Handles COMPort.DataReceived
Dim RXByte As Byte
Do
'----- Start of communication protocol handling -----------------------------------------------------------
' The code between the two lines does the communication protocol. In this case, it simply emties the
' receive buffer and converts it to text, but for all practical applications, you must replace this part
' with a code, which can collect one entire telegram by searching for the telegram
' delimiter/termination. In case of a simple ASCII protocol, you may just use ReadLine and receive
' in a global string instead of a byte array.
' Because this routine runs on a thread pool thread, it does not block the UI, so if you have any data
' convertion, encryption, expansion, error detection, error correction etc. to do, do it here.
RXCnt = 0
Do
RXByte = COMPort.ReadByte
RXArray(RXCnt) = LookUpTable(RXByte >> 4) ' Convert each byte to two hexadecimal characters
RXCnt = RXCnt + 1
RXArray(RXCnt) = LookUpTable(RXByte And 15)
RXCnt = RXCnt + 1
RXArray(RXCnt) = " "
RXCnt = RXCnt + 1
SpaceCount = (SpaceCount + 1) And 31 ' Insert spaces and CRLF for better readability
If SpaceCount = 0 Then ' Insert CRLF after 32 numbers
RXArray(RXCnt) = Chr(13) ' CR
RXCnt = RXCnt + 1
RXArray(RXCnt) = Chr(10) ' LF
RXCnt = RXCnt + 1
Else
If (SpaceCount And 3) = 0 Then ' Insert two extra spaces for each 4 numbers
RXArray(RXCnt) = " "
RXCnt = RXCnt + 1
RXArray(RXCnt) = " "
RXCnt = RXCnt + 1
End If
End If
Loop Until (COMPort.BytesToRead = 0)
'----- End of communication protocol handling -------------------------------------------------------------
Me.Invoke(New MethodInvoker(AddressOf Display)) ' Start "Display" on the UI thread
Loop Until (COMPort.BytesToRead = 0) ' Don't return if more bytes have become available in the meantime
End Sub
' Text display routine, which appends the received string to any text in the Received TextBox.
Private Sub Display()
Received.AppendText(New String(RXArray, 0, RXCnt))
End Sub
System.Text.Encoding.Unicode.GetString(bytes) 'bytes is your byte array'
Notice the first line after Do in your inner loop:
RXByte = COMPort.ReadByte
This is the only point in your code where you have the actual byte value read from the COM port. After this point the code converts the byte into two hex values using bit-shifting. You should create a global variable of string type and append the read byte value to this string before it is lost.
Add the following line immediately after the above line:
YourString &= Convert.ToChar(RXByte).ToString()
where YourString is your global string variable.
Note that you can attain some efficiency by using StringBuilder instead of string, but I'm leaving that for you as exercise.
I have string
'TEST1, TEST2, TEST3'
I want to have
'TEST1,TEST2,TEST3'
Is in powerbuilder is a function like replace, substr or something?
One way is to use the database since you probably have an active connection.
string ls_stringwithspaces = "String String String String"
string ls_stringwithnospace = ""
string ls_sql = "SELECT replace('" + ls_stringwithspaces + "', ' ', '')"
DECLARE db DYNAMIC CURSOR FOR SQLSA;
PREPARE SQLSA FROM :ls_sql USING SQLCA;
OPEN DYNAMIC db;
IF SQLCA.SQLCode > 0 THEN
// erro handling
END IF
FETCH db INTO :ls_stringwithnospace;
CLOSE db;
MessageBox("", ls_stringwithnospace)
Sure there is (you could have easily found it in the help) but it is not quite helpful, though.
Its prototype is Replace ( string1, start, n, string2 ), so you need to know the position of the string to replace before calling it.
There is a common wrapper for this that consists of looping on pos() / replace() until there is nothing left to replace. The following is the source code of a global function:
global type replaceall from function_object
end type
forward prototypes
global function string replaceall (string as_source, string as_pattern, string as_replace)
end prototypes
global function string replaceall (string as_source, string as_pattern, string as_replace);//replace all occurences of as_pattern in as_source by as_replace
string ls_target
long i, j
ls_target=""
i = 1
j = 1
do
i = pos( as_source, as_pattern, j )
if i>0 then
ls_target += mid( as_source, j, i - j )
ls_target += as_replace
j = i + len( as_pattern )
else
ls_target += mid( as_source, j )
end if
loop while i>0
return ls_target
end function
Beware that string functions (searching & concatenating) in PB are not that efficient, and an alternative solution could be to use the FastReplaceall() global function provided by the PbniRegex extension. It is a c++ compiled plugin for PB classic from versions 9 to 12.
I do that:
long space, ll_a
FOR ll_a = 1 to len(ls_string)
space = pos(ls_string, " ")
IF space > 0 THEN
ls_string= Replace(ls_string, space, 1, "")
END IF
NEXT