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 7 years ago.
Improve this question
I have a list of data, distributed with a non-homogeneous pattern, on 3 columns. The challenge is to write a vba code "smart enough" to copy and paste all these numbers on one column, putting them in order, one below the other one: 1, 2, 3, 4, 4.1, 4.2 etc.. without missing any of them.
Could someone help me in this task? Because I see a lot of complexity and I have no idea how to manage it. Thank you!
As I understand it, you're looking to order this in a specific way that isn't necessarily how Excel would sort by default. The values look like version numbers or nested task IDs.
Stack Overflow isn't really a "solve your problem for you" kind of place, but I can definitely get you started. Here's what you'll need to do:
Get all the values, preferably into a Collections object. Make sure to omit blank cells.
Convert each value into a new format which a) is sortable, and b) can be reverted to the original format. For example, let's say these are version numbers, and any given number can be as high as 999, and there can be up to 4 items (e.g. 123.10.15.9 is valid, as is 9.5). Convert these to the form 000000000000 (that's 12 0s). You can do this by using Split() to divide the values using the "." delimiter, then padding the value out. This might look something like this:
.
'Converts 1 => 001000000000
' 1.1 => 001001000000
' 2.4.7 => 002004007000
' 65.339.1 => 065339001000
Function ConvertToSortableVersionNumber(value As String) As String
'Add all the parts of the value (. delimited) to a collection
Dim vnPart As Variant
Dim error As Boolean: error = False
Dim Parts As Collection
Set Parts = New Collection
For Each vnPart In Split(value, ".")
'Make sure this can actually be formatted as needed.
If Len(vnPart) > 3 Then
error = True
Exit For
End If
'Add this part to the Parts collection
Parts.Add vnPart
Next vnPart
'Now make sure there are 4 parts total
If Parts.Count > 4 Then error = True
'Check for errors
If error Then
'There is an error. Handle it somehow
End If
'If there are less than 4 items in the collection , add some
While Parts.Count < 4
Parts.Add ("000")
Wend
'Now, assemble the return value
Dim retVal As String
Dim item As Variant
For Each item In Parts
retVal = retVal & Right(String(3, "0") & item, 3)
Next item
'All set!
ConvertToSortableVersionNumber = retVal
End Function
Sort the collection (this page has a good example of sorting a collection in memory).
Create an array with new values converting back to the original format (much easier since the inputs will be highly standardized).
Write the array to a new range--and you're done!
Take a stab at it. I think you'll find that Stack Overflow is much more helpful once you can show the work you've already done, what you've tried, and what specifically is giving you trouble.
Good luck!
If you have 2010 or later the following formula will do it:
=IFERROR(SUBSTITUTE(SUBSTITUTE(AGGREGATE(15,6,--SUBSTITUTE($A$1:$C$10,".","000")*--(1 & REPT("0",9-LEN(SUBSTITUTE($A$1:$C$10,".","000")))),ROW(1:1)),"0000",""),"000","."),"")
If you have 2007 or earlier than it will need to be an array formula:
=IFERROR(SUBSTITUTE(SUBSTITUTE(SMALL(IF($A$1:$C$10<>"",--SUBSTITUTE($A$1:$C$10,".","000")*--(1 & REPT("0",9-LEN(SUBSTITUTE($A$1:$C$10,".","000"))))),ROW(1:1)),"0000",""),"000","."),"")
Being an array formula it must be confirmed with Ctrl-Shift-Enter instead of Enter when leaving edit mode.
Column E is the first formula and Column F is the second.
Related
I asked a question on Stack Overflow a few days ago asking for a solution for copying email support forms and pasting the data into the appropriate text fields on a form. I got an answer which solved my problem - until I went to go use the tool and realized a problem.
I am using this code:
'Service Plan Description
For i = 0 To lines.Count - 1
If lines(i).StartsWith("Service Plan Desc. :") Then
StartLine = i
Exit For
End If
Next
tbx_ServicePlanDescription.Text = lines(StartLine).Split(":"c)(1).Trim 'Put sorted data into textbox
And when I copy the following text into the clipboard to test the Service Plan textbox:
Maint:AbloEnterprise S/W AddOn (5)
It only pastes 'Maint' in the textbox because the code purposely removes the colons.
So my question is: What would be a way to overcome this?
I used the Split(Char[], Int32) method to limit how many parts the split would split the string into, as suggested in the comments, like this:
tbx_ServicePlanDescription.Text = lines(StartLine).Split({":"c}, 2)(1).Trim()
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 4 years ago.
Improve this question
I have an array that contains characters converted from a word via .ToCharArray method. I would like to check how many times a letter occurred in this array (word). How can I do this?
One way is a lookup:
Dim letterLookup = yourCharArray.ToLookup(Function(c) c)
' For example the letter e, note that it's case sensitive '
Dim eLetterCount As Int32 = letterLookup("e"c).Count()
This is efficient and has the advantage that you can even check letters which aren't contained in the String/Char(), you will get 0 as result.
By the way, you don't need to use ToCharArray, you could use this code on with original string.
If you wanted to list all contained letters:
Dim allLetters As IEnumerable(Of Char) = letterLookup.Select(Function(kv) kv.key)
If you wanted to ignore the case, so treat e and E as equal:
Dim letterLookup = yourCharArray.tolookup(Function(c) c, StringComparer.CurrentCultureIgnoreCase)
For example the word 'tent'. The program would check which letter
occurs more than once (t) and find the position in the array (in this
case 0,3). It will also find the position in the array of the other
letters.
Then i would use a different approach also using LINQ:
Dim duplicateLetterPositions As Dictionary(Of Char,List(Of Integer)) = yourCharArray.
Select(Function(c, index) New With {.Char = c, .Index = index}).
GroupBy(Function(c) c.Char).
Where(Function(grp) grp.Count > 1).
ToDictionary(Function(grp) grp.Key, Function(grp) grp.Select(Function(x) x.Index).ToList())
There are a few posts open on this topic however none seem to fully do what I need. I have done a little bit of programming however I have never done anything with VBA. Every day I receive a series of emails varying from 10 to 50 all containing a subject line starting with [Tk#*******] New Request ( * = 7 digit number)
Then inside the body text there is a form that looks like this:
Body Text
I then have an excel sheet set up with 'Username' in 'C', 'Company' in 'G', 'valid until' in 'H' and 'Ticket' in 'I'. I would like to extract first the 7 digit ticket number from the subject and put it in the excel 'Ticket' field, then just the 'smithjoh' part from the login field and place it in 'Username', then the External company listed to 'Company' and finally the Expiration date into 'valid until'.
First I would like to know if this is possible to do as it is extracting specific sections of the data and if so if someone could help me out with making this work that'd be most appreciated. I have attempted to do it myself however lack of experience has left me clueless therefor there is nothing to work with unfortunately. If this could be made it would help me out a lot as it would automate a very tedious manual task.
Thanks,
Mark
Ok, if you are grabbing the body and title without issue then you just need to do string manipulations. Read them into a variable each. Assuming that your subject is litterally "TK#******* New Request" then this should get you started. Basically repeat this logic for each part you want to pull out. Once you have the values in variables you can then put those values into cells.
Dim sSubject as string
Dim sBody as string
Dim sTicket as string
Dim sLogin as string
Dim lLoginPos as long
Dim iLoginLength as integer
sTicket = Mid(sSubject,4,7) 'start 4th char and grab 7 ... if you actually have the brackets in the subject then do 5,7
lLoginPos = InStr(sBody, "emea") + 5 'if they aren't all emea you will need to key off the "Req on behalf name" and add more to the result the result will be the e in emea so add 5 to get past that to the login.
iLoginLength = InStr(sBody, "Req on behalf mail") - lLoginPos ' you might need to subtract an additional 1 or 2 if your result isn't perfect. Not sure what the blank white spaces in your screenshot will do here.
sLogin = Mid(sBody,lLoginPos,iLoginLength) ' grabs that username.
With Sheets("Sheet1")
cells(1,3) = sLogin ' puts that into Row 1 Colum 3 (C) Cells is R1C1 ... backwards from the normal way you think of excel
End With
Use other string variables for all the other parts you want to grab and just repeat the logic of finding the starting place and ending place and then using mid to put it into a variable.
Give it a shot filling out the rest and if you get stuck, post your code up to that point and let us know what line is giving you trouble. Don't forget to turn on your locals window and use your F8 key to step through the code one line at a time so that you can see exactly what is going on. This is especially useful with string manipulations.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
Hi i really need some help with this, I need to make a multiple choice question program that reads the questions and answers from 2 different text files (notepad files)
but when I try I cant seem to get it working. i have tried loops but that didn't work then I tried arrays but that didn't meet the requirements of reading form a text file
So I come to you all I need help is with reading a text file line by tine and then updating it when a new question needs to be given
I cannot 1 read the line by line (questions.txt) and i need to have match the question which are in answers.txt then i need to update it when next question is clicked
VB.Net
Program i need to create must do the following
Questions and answers should be loaded from a file called questions.txt and answers.txt respectively
-Questions should also appear in random order, every time program is executed
-update form for next question
-keep track on how many questions are correct
Any resources or tutorials on any of the above would be muchly appreciated
Total edits: 198305769 lol. Cleaned up the answer, and this should get you nearly complete. Cheers.
Declare a global variable (integer); that's where you'll assign the amount of questions the user has answered:
Public Class Form1
Dim keepScore As Integer = 0
Not the neatest, but it appends each line from a selected text file into an array and then you can iterate through it.
Dim ofd As New OpenFileDialog
ofd.ShowDialog()
Dim xstr = ofd.FileName
Dim questions() As String = IO.File.ReadAllLines(ofd.FileName)
Dim answers() As String = IO.File.ReadAllLines(ofd.FileName)
Dim sw As New StringBuilder
Dim i As Integer = 0
Do Until i = questions.Count()
sw.AppendLine(Trim(questions(i)))
MsgBox(questions(i)) 'Only added this so you can see the lines
i = i + 1
Loop
Do Until i = answers.Count()
sw.AppendLine(Trim(answers(i)))
MsgBox(answers(i)) 'Only added this so you can see the lines
i = i + 1
Loop
Add onto the end of this function an if statement:
If CorrectAnswer.Checked = True 'Assuming you are using a RadioButton Group, or CheckBox
keepScore = keepScore + 1
End If
Here is a quick number randomiser, assuming you have 20 questions (change the 20 accordingly to whatever amount of questions you have):
Randomize()
Dim i As Integer = CInt(Int(20 * Rnd() + 1))
MsgBox(i)
Best of luck.
first time questioner here. Thanks in advance for any help you can give.
I'm trying to read a bunch of data from a spreadsheet, chop it up, then throw it into a database. I would rather not do things this way, but it's a basic reality of dealing with accountant-types. Thankfully these spreadsheet reports are very consistent. Anyway, I'm using LINQ for SQL to handle the object-to-reference stuff and I'm using Microsoft.Office.Interop to get my Excel on.
I read through a directory full of .xls and for each one, I'm opening the file, getting a couple of specific data from some specific cells, and then getting a range of cells to pick out values.
Private Sub ProcessAFile(ByVal f As FileInfo)
thisFile = openApp.Workbooks.Open(f.fullName)
thisMonth = Split(thisChart.Range("D6").Value, "-").Last.Trim
thisFY = thisChart.Range("L7").Value
thisWorkArea = thisChart.Range("A14", "L51").Value2
openApp.Workbooks.Close()
...
thisWorkArea was Dimmed as a global:
Dim thisWorkArea As Object(,)
I'm getting both strings and ints in my range between A14 and L51, so making it an Object array makes sense here. I don't want to go through each row and pick out ranges in Excel, I want to just read it once and then close it.
So I'm getting the following exception:
System.IndexOutOfRangeException was unhandled
Message=Index was outside the bounds of the array.
in this function:
Private Sub fillCurrMonth()
Dim theseRows As Integer() = {0, 2, 3, 5}
For Each i In theseRows
Dim thisMonth As New Month
'make sure category is in Database
thisMonth.Dept = thisDeptName
thisMonth.FY = thisFY
thisMonth.Category = thisWorkArea(i, 0)
...
"Month" above refers to a LINQ entity. It's nothing fancy.
That last line there is where I'm catching the exception. In my watch, I find that thisWorkArea has a length of 456 and (0,0) -> "Inpatient"{String}
So why am I getting this exception? I put this in your expert hands. I'm still rather new to vb.net, so maybe I'm just missing something fundamental.
Excel uses 1-based indicies. This stems from it using VB as it's in-app programming language which traditionally used 1-based indicies.
You'll find Excel returned an array defined as thisWorkArea(1 To 11, 1 To 37) As Object
'Fix excel's 1 based index
Dim oData(UBound(xData) - 1, UBound(xData, 2) - 1) As Object
For i As Integer = 1 To UBound(xData)
For ii As Integer = 1 To UBound(xData, 2)
oData(i - 1, ii - 1) = xData(i, ii)
Next
Next