extracting multiple values from a string VB.NET - arrays

I am dealing with http URLs, all the URLs are correct but some are like:
http://site.com/abgAz1nBs.jpg%20http://site.com/adtEh96Wj.jpg%20http://site.com/acum1N6qN.jpg
so basically these are 3 URLS. I need them to be separated. But it is not the only problem, I need to use "IF" statement to confirm that there is a string that contains multiple "http://" because other URLs are correct

Try this:
Dim strURLToEvaluate As String = "http://site.com/abgAz1nBs.jpg%20http://site.com/adtEh96Wj.jpg%20http://site.com/acum1N6qN.jpg"
Dim strURLs As String() = Strings.Split(strURLToEvaluate, "%20http://")
If strURLs.Length > 1 Then MsgBox("More than one URL!")
For Each strURL In strURLs
If Strings.Left(strURL, Len("http://")) <> "http://" Then strURL = "http://" & strURL
MsgBox(strURL)
Next strURL

You can use the following algorithm:
Check if the string contains "%20http" (using String.Contains).
If yes, split at "%20http" (using String.Split).
Add "http" at each of the split strings except the first one (using normal string concatenation).
Implementing these steps should be easy and will be (deliberately) left as an exercise to the reader. In fact, after you have implemented them correctly, you might realize that you can skip the first step altogether.

Related

How to parse and address a json matrix array in Excel-VBA?

I need to parse JSON text to a JSON object in Excel-VBA. The JSON text includes a matrix/array. Then I need to address it (set a VBA variable to the value).
My code had been working parsing a nested/keyed JSON text with "JsonConverter.parseJSON" method. But I do not know how to address new array object (or technically if the "parse" is working correctly.
Dim jsonResults As String
Dim jsonObj As Dictionary
Set travelDist As Number
Set jsonResults = '{"distances":[[0,97641],[97415,0]],"times":[[0,4189],[4183,0]],"weights":[[0.0,5653.726],[5644.176,0.0]],"info":{"copyrights":["GraphHopper","OpenStreetMap contributors"]}}'
Set jsonObj = JsonConverter.ParseJson(jsonResults) \This worked with the old JSON text keyed value structure.
travelDist = VBA.Val(jsonObj.Item("distances")(1)) \This DOESN'T work. It worked with Keyed Object Values. The goal is to set travelDist to in this example, 97641.
The current code seems to have a type mismatch.
The goal is to set a VBA variable to 97641. Please let me know how to include required files/definitions etc. if the solution is including additional types or methods.
There's no reason to declare jsonObj as a dictionary and unless Number is a well defined user-defined type of some sort, I don't think declaring travelDist as Number will work. Use Double instead. And always use Option Explicit on the very top.
Also the double quotes in the JSON string need to be escaped somehow. You can either double them:
jsonResults = "{""distances"":[[0,97641],[97415,0]],""times"":[[0,4189],[4183,0]],""weights"":[[0.0,5653.726],[5644.176,0.0]],""info"":{""copyrights"":[""GraphHopper"",""OpenStreetMap contributors""]}}"
or replace them with single quotes:
jsonResults = "{'distances':[[0,97641],[97415,0]],'times':[[0,4189],[4183,0]],'weights':[[0.0,5653.726],[5644.176,0.0]],'info':{'copyrights':['GraphHopper','OpenStreetMap contributors']}}"
or you can just store the string in a cell in one of your worksheets and load it from there:
Dim sht As Worksheet
Set sht = ThisWorkbook.Worksheets("Name of your Worksheet")
Set jsonObj = JsonConverter.ParseJson(sht.Range("A1"))
Visualizing the JSON structure might help you understand it better:
So basically what you need to do is access the 2nd item, of the 1st item, of the distances array/collection, keeping in mind that the 1st item of the distances array is also an array/collection itself.
The way to do this would be the following:
Option Explicit
Sub test()
Dim jsonObj As Object
Dim jsonResults As String
Dim travelDist As Double
jsonResults = "{""distances"":[[0,97641],[97415,0]],""times"":[[0,4189],[4183,0]],""weights"":[[0.0,5653.726],[5644.176,0.0]],""info"":{""copyrights"":[""GraphHopper"",""OpenStreetMap contributors""]}}"
Set jsonObj = JsonConverter.ParseJson(jsonResults)
travelDist = jsonObj("distances")(1)(2)
Debug.Print travelDist 'the result is printed in the immediate window
End Sub
Finally, I assume that since you've used this before, you know you need to add this JSON parser to your project, as well as a reference to Microsoft Scripting Runtime (VBE>Tools>References>...)

Check if a string contains all other strings

I am trying to code a part of a software where I try to show the results that match search criteria.
I have a textbox where I can type one or more words I want to search and a listview that contains 4 different columns and a dozen rows. The idea is that each listview row contains lots of words and I want to see only the rows that contain all the words I have typed in the textbox. I have finished the code that searches for one term only. The problem I am having is that I don't fully understand how to do the same, but using multiple terms instead of one term only.
In the textbox, I write the words I want to search separated by a space. I have a variable where I keep the whole content of the listview row separated by : (example => col1row1content:col1row2content:col1row3content,etc). Summarizing, I want to check if a string (the full content of a row) contains all other strings (each word I have typped in the textbox).
This is the code I have implemented:
Dim textboxFullContentArray As String() = textboxSearch.Split(New Char() {" "c})
Dim Content As String
Dim containsAll As Boolean = False
Dim wholeRowContent(listviewMain.Items.Count - 1) As String ' each index of the array keeps the entire row content (one array contains all 4 cells of the row)
' wholeRowContent contains in one index the entire content of a row. That means,
' the index contains the 4 cells that represent an entire row.
' The format is like "rowData1:rowData2:rowData3:rowData4" (omitted for simplicity)
For Q As Integer = 0 To listviewMain.Items.Count - 1
For Each Content In textboxFullContentArray
If wholeRowContent(Q).ToLower.Contains(Content) Then
containsAll = True
' rest of the code...
ElseIf Not wholeRowContent(Q).ToLower.Contains(Content) Then
containsAll = False
Exit For
End If
Next
Next
But of course, this code is showing false positives and I think it's not a good solution. I think it must be much easier and I am overcomplicating the concept.
I am using VB.Net 2013
You can determine whether a String contains all of a list of substrings with a single line of code:
If substrings.All(Function(s) str.IndexOf(s, StringComparison.OrdinalIgnoreCase) >= 0) Then
Notice that I have actually implemented a case-insensitive comparison, rather than using ToLower or ToUpper.
It may not seem as neat to call IndexOf rather than Contains but guess what: Contains actually calls IndexOf internally anyway:
public bool Contains(string value)
{
return this.IndexOf(value, StringComparison.Ordinal) >= 0;
}
You can write your own extension methods if you want a case-insensitive Contains method:
<Extension>
Public Function Contains(source As String,
value As String,
comparisonType As StringComparison) As Boolean
Return source.IndexOf(value, comparisonType) >= 0
End Function
Your If/Else looks like it could be simplified. I would set your containsAll value to true outside the nested loops, and only if you encounter a "Content" in "textboxFullContentArray" that is not contained in wholeRowContent(Q) you set containsAll to false, otherwise do nothing.
Also, one way to see what's going on is to print statements with the values that are being compared throughout your function, which you can read through and see what is happening at runtime when the false positives occur.
After some hours looking for a simple and effective solution (and trying different codes), I have finally found this solution that I adapted from: Bad word filter - stackoverflow
For Q As Integer = 0 To listviewMain.Items.Count - 1
If textboxFullContentArray.All(Function(b) wholeRowContent(q).ToLower().Contains(b.ToLower())) Then
' my code
End If
Next

Find Array index that contains string

I have file with tags and targets, this is example:
TAG1|TARGET1,TARGET2
TAG2|TARGET3,TARGET4
I start by creating String Array using File.ReadAllLines
Dim MAIN As String() = File.ReadAllLines("")
At some point I have one of targets and I need to know what was the tag index (which array line is it), so for example if I have TARGET3 I want to know it's in second line so it's in MAIN(1) and then I can grab TAG = TAG2.
I can't get it working, I tried few methods:
Array.IndexOf(MAIN,"TARGET3")
always returned -1, it worked with full string tho,
Array.IndexOf(MAIN,"TAG2|TARGET3,TARGET4")
returned 1. I tried with Array.FindIndex, was the same.
So my question is: how to get index of partial array item. Thank you for any help.
You can use Linq to search your array in this way
Dim search = "TARGET3"
Dim line = MAIN.FirstOrDefault(Function(x) x.Contains(search))
This will return directly the line with the matching word

MS Access - open a form taking a field value from a previous form

I have a form in an MS Access database which lists all the landowners consulted with for a new electricity line. At the end of each row is a button which opens another form, showing the details of all consultation, offers made etc.
I am trying to use vb in MS Access to take the contactID and automatically put it in a field in the details form, so that landowner's consultation details will pop up automatically. I am not a vb programmer at all (I have a comp sci degree mostly in Java and I'm currently working as a GIS analyst but it's a small company so I've been asked to get an Access database working).
I want to say
[detailsForm]![contactID] = [landownerlist]![ID]
in a way that vb and access will be happy with. Then I can see if I'm on the right track and if it will actually work! What I have above does not actually work. It won't compile.
From Kaliana
If you wish to open a form to a new record and to set the ID there, you can use Openargs, an argument of Openform:
DoCmd.OpenForm "FormName",,,,acFormAdd,,Me.ID
The opened form would also need some code:
If Me.Openargs<>vbNullstring Then
Me.Id = Me.Openargs
End If
It is also possible to find:
Forms!LandownersList.Recordset.FindFirst "ID=" & Me.ID
or fill in a value:
Forms!LandownersList!Id = Me.ID
on the form being opened from the calling form.
You may want to look into the code that is behind these buttons. If you are using a docmd.openform you can set the 4th Setting to a where clause on openning the next form.
DoCmd.OpenForm "OpenFormName", acNormal, , "[contactID] = " _
& [detailsForm]![contactID] , acFormEdit, acWindowNormal
This assumes contact ID is numeric and doesn't require any quotes.
Using open args is the generally accepted solution, as alluded to by others. This just falls under the category of "For you edification":) One of the problems with using open args is that unless you are careful with your comments it's easy to forget what they were supposed to mean. Were you passing more than one? Which is which? How did I do it here? How did I do it there etc. For my own money, I standardized to this (below) so I can always pass more than one argument without fear, and when I review my code a year from now, I can still see what's what without a huge hassle:
Option Explicit
'Example use: DoCmd.OpenForm "Example", OpenArgs:="Some Filter|True"
Public Enum eForm1Args
eFilter = 0
eIsSpecial = 1
End Enum
Private m_strArgs() As String
Public Property Get Args(ByVal eForm1Args As eForm1Args) As String
Args = m_strArgs(eForm1Args)
End Property
Private Sub Form_Open(Cancel As Integer)
m_strArgs = Split(Nz(Me.OpenArgs, vbNullString), "|")
If LenB(Me.Args(eFilter)) Then Me.Filter = Me.Args(eFilter)
End Sub
Private Sub Command1_Click()
If LCase$(Me.Args(eIsSpecial)) = "true" Then
'Do something special
End If
End Sub
As previously posted OpenArgs is great for this. One trick I have learned is that it is easy to pass in multiple parameters if required as a delimited string (comma for example), the target form can then access these values using the Split() function thus:
StringArrayVariable()= Split(me.OpenArgs,",")
Me.textbox= StringArrayVariable(0)
Me.textbox1= StringArrayVariable(1)
etc.
This is air code so check out the helpfile for Split().
It is also possible to pass objects in OpenArgs as well, it requires some manual memory pointer manipulation and I don't have the code to hand but I'm sure a Google search will find some examples. This technique can cause some random crashes though. Be Warned!

One line code examples in various languages for MD5

I'm looking for one line code examples in various languages for getting a valid MD5 result (as a string, not a bytehash or what have you). For instance:
PHP:
$token = md5($var1 . $var2);
I found VB especially troublesome to do in one line.
C#:
string hash = System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(input, "md5");
VB is virtually the same.
Here it is not using the System.Web namespace:
string hash = Convert.ToBase64String(new System.Security.Cryptography.MD5CryptoServiceProvider().ComputeHash(System.Text.Encoding.UTF8.GetBytes(input)));
Or in readable form:
string hash =
Convert.ToBase64String
(new System.Security.Cryptography.MD5CryptoServiceProvider()
.ComputeHash
(System.Text.Encoding.UTF8.GetBytes
(input)
)
);
There is a kind of universality in how this is to be accomplished. Typically, one defines a routine called md5_in_one_line (or Md5InOneLine) once, and uses it all over the place, just as one would use a library routine.
So for example, once one defines Md5InOneLine in C#, it's an easy one-liner to get the right results.
Python
token = __import__('md5').new(var1 + var2).hexdigest()
or, if md5 is alrady imported:
token = md5.new(var1 + var2).hexdigest()
Thanks to Greg Hewgill
Aren't you really just asking "what languages have std. library support for MD5?" As Justice said, in any language that supports it, it'll just be a function call storing the result in a string variable. Even without built-in support, you could write that function in any language!
Just in case you need VBScript:
download the MD5 class from webdevbros and then with one line:
hash = (new MD5).hash("some value")
Does it really matter if you can do MD5 in one line. If it's that much trouble that you can't do it in VB in 1 line, then write your own function. Then, when you need to do MD5 in VB in one line, just call that function.
If doing it all in 1 line of code is all that important, here is 1 line of VB. that doesn't use the System.Web Namespace.
Dim MD5 As New System.Security.Cryptography.MD5CryptoServiceProvider() : Dim HashBytes() As Byte : Dim MD5Str As String = "" : HashBytes = MD5.ComputeHash(System.Text.Encoding.UTF8.GetBytes("MyString")) : For i As Integer = 0 To HashBytes.Length - 1 : MD5Str &= HashBytes(i).ToString("x").PadLeft(2, "0") : Next
This will hash "MyString" and store the MD5 sum in MD5Str.
Coldfusion has a bunch of hashing algorithms, MD5 is the default.
cfset var md5hashresult = hash("string to hash")

Resources