Sort a String array - regex

I have as input the string in the below format
"[1_5,3,7,1],[1_2,4,1,9],[],[1_1,,4,,,9,2]"
What I need to obtain is the same string but with the number after the _ sorted:
"[1_1,3,5,7],[1_1,2,4,9],[],[1_1,2,4,9,,,]"
Dim tmprequestedArea_selectionAreaIn As String = "[1_5,3,7,1],[1_2,4,1,9],[],[1_1,,4,,,9,2]"
tmprequestedArea_selectionAreaIn = Regex.Replace(requestedArea_selectionAreaIn,"\],\[","#")
tmprequestedArea_selectionAreaIn = Regex.Replace(tmprequestedArea_selectionAreaIn,"\[|\]","")
bracList.AddRange(tmprequestedArea_selectionAreaIn.Split(New Char() {"#"c}, StringSplitOptions.None ))
If sortNumber Then
'Split braclist by _ and puts the value in strList
'If after _ is only one number put only that number, else split it by char "," and put in strList the join of the split by , array
'Sort the array
'in previous example strList will contain a,b,c in position 0 and _d_f (instead of f,d) in position 1
For i As Integer = 0 To bracList.Count -1
Dim tmp As String()
Dim tmpInt As New System.Collections.Generic.List(Of Integer)
If Not(String.IsNullOrEmpty(bracList(i))) Then
Dim tmpRequested As String = bracList(i).Split(New Char() {"_"c})(0)
Dim tmpSelection As String = bracList(i).Split(New Char() {"_"c})(1)
If tmpSelection.Contains(",") Then
tmp = tmpSelection.Split(New Char() {","c})
For j As Integer = 0 To tmp.Length -1
tmpInt.Add(Convert.toInt32(tmp(j)))
Next
tmpInt.Sort
strList.Add("[" + tmpRequested + "_" + String.Join(",",tmpInt ) + "]")
Else
strList.Add("[" + tmpRequested + "_" + tmpSelection + "]" )
End If
Else
strList.Add("[]")
End If
Next i
I'm looking for a better way to manage it.

Try this, as a possible substitute for what you're doing now.
Given this input string:
Dim input As String = "[1_5,3,7,1],[1_2,4,1,9],[],[1_1,,4,,,9,2]"
Note: this will also deal with decimal values without changes. E.g.,
"[1_5.5,3.5,7,1],[1_2.564,4,2.563,9],[],[1_1,,4.23,,,9.0,2.45]"
You can extract the content of the brackets with this pattern: \[(.*?)\] and use Regex.Matches to return a MatchCollection of all the substrings that match the pattern.
Then use a StringBuilder as a container to rebuild the string while the parts are being treated.
Imports System.Linq
Imports System.Text.RegularExpressions
Dim pattern As String = "\[(.*?)\]"
Dim matches = Regex.Matches(input, pattern, RegexOptions.Singleline)
Dim sb As New StringBuilder()
For Each match As Match In matches
Dim value As String = match.Groups(1).Value
If String.IsNullOrEmpty(value) Then
sb.Append("[],")
Continue For
End If
Dim sepPosition As Integer = value.IndexOf("_"c) + 1
sb.Append("[" & value.Substring(0, sepPosition))
Dim values = value.Substring(sepPosition).Split(","c)
sb.Append(String.Join(",", values.Where(Function(n) n.Length > 0).OrderBy(Function(n) CDec(n))))
sb.Append(","c, values.Count(Function(n) n.Length = 0))
sb.Append("],")
Next
Dim result As String = sb.ToString().TrimEnd(","c)
If you don't know about LINQ, this is what it's doing:
String.Join(",", values.Where(Function(n) n.Length > 0).OrderBy(Function(n) CDec(n)))
values is an array of strings, generated by String.Split().
values.Where(Function(n) n.Length > 0): creates an Enumerable(Of String) from values Where the content, n, is a string of length > 0.
I could have written values.Where(Function(n) Not String.IsNUllOrEmpty(n)).
.OrderBy(Function(n) CDec(n))): Orders the resulting Enumerable(Of String) using the string value converted to Decimal and generates an Enumerable(Of String), which is passed back to String.Join(), to rebuild the string, adding a char (","c) between the parts.
values.Count(Function(n) n.Length = 0): Counts the elements of values that have Length = 0 (empty strings). This is the number of empty elements that are represented by a comma, appended at the end of the partial string.

If you are looking for a "way"
I think it is easier to fetch each char of the string and if it is a number you put it in array (and when the char is ']' you start new array) the sort the arrays and replace each number from the string with it's sorted number (so you will just do allocation without the need to reconstruct with regular expression
I wish that I had Visual Studio to provide you the code (it is joyful to code a riddle) ^_^
ps:for the commas you can use a counter for each blank commas an the put it in the end

Related

Using Regex To find total occurrence of &T [duplicate]

I have a string (for example: "Hello there. My name is John. I work very hard. Hello there!") and I am trying to find the number of occurrences of the string "hello there". So far, this is the code I have:
Dim input as String = "Hello there. My name is John. I work very hard. Hello there!"
Dim phrase as String = "hello there"
Dim Occurrences As Integer = 0
If input.toLower.Contains(phrase) = True Then
Occurrences = input.Split(phrase).Length
'REM: Do stuff
End If
Unfortunately, what this line of code seems to do is split the string every time it sees the first letter of phrase, in this case, h. So instead of the result Occurrences = 2 that I would hope for, I actually get a much larger number. I know that counting the number of splits in a string is a horrible way to go about doing this, even if I did get the correct answer, so could someone please help me out and provide some assistance?
Yet another idea:
Dim input As String = "Hello there. My name is John. I work very hard. Hello there!"
Dim phrase As String = "Hello there"
Dim Occurrences As Integer = (input.Length - input.Replace(phrase, String.Empty).Length) / phrase.Length
You just need to make sure that phrase.Length > 0.
the best way to do it is this:
Public Function countString(ByVal inputString As String, ByVal stringToBeSearchedInsideTheInputString as String) As Integer
Return System.Text.RegularExpressions.Regex.Split(inputString, stringToBeSearchedInsideTheInputString).Length -1
End Function
str="Thisissumlivinginsumgjhvgsum in the sum bcoz sum ot ih sum"
b= LCase(str)
array1=Split(b,"sum")
l=Ubound(array1)
msgbox l
the output gives u the no. of occurences of a string within another one.
You can create a Do Until loop that stops once an integer variable equals the length of the string you're checking. If the phrase exists, increment your occurences and add the length of the phrase plus the position in which it is found to the cursor variable. If the phrase can not be found, you are done searching (no more results), so set it to the length of the target string. To not count the same occurance more than once, check only from the cursor to the length of the target string in the Loop (strCheckThisString).
Dim input As String = "hello there. this is a test. hello there hello there!"
Dim phrase As String = "hello there"
Dim Occurrences As Integer = 0
Dim intCursor As Integer = 0
Do Until intCursor >= input.Length
Dim strCheckThisString As String = Mid(LCase(input), intCursor + 1, (Len(input) - intCursor))
Dim intPlaceOfPhrase As Integer = InStr(strCheckThisString, phrase)
If intPlaceOfPhrase > 0 Then
Occurrences += 1
intCursor += (intPlaceOfPhrase + Len(phrase) - 1)
Else
intCursor = input.Length
End If
Loop
You just have to change the input of the split function into a string array and then delare the StringSplitOptions.
Try out this line of code:
Occurrences = input.Split({phrase}, StringSplitOptions.None).Length
I haven't checked this, but I'm thinking you'll also have to account for the fact that occurrences would be too high due to the fact that you're splitting using your string and not actually counting how many times it is in the string, so I think Occurrences = Occurrences - 1
Hope this helps
You could create a recursive function using IndexOf. Passing the string to be searched and the string to locate, each recursion increments a Counter and sets the StartIndex to +1 the last found index, until the search string is no longer found. Function will require optional parameters Starting Position and Counter passed by reference:
Function InStrCount(ByVal SourceString As String, _
ByVal SearchString As String, _
Optional ByRef StartPos As Integer = 0, _
Optional ByRef Count As Integer = 0) As Integer
If SourceString.IndexOf(SearchString, StartPos) > -1 Then
Count += 1
InStrCount(SourceString, _
SearchString, _
SourceString.IndexOf(SearchString, StartPos) + 1, _
Count)
End If
Return Count
End Function
Call function by passing string to search and string to locate and, optionally, start position:
Dim input As String = "Hello there. My name is John. I work very hard. Hello there!"
Dim phrase As String = "hello there"
Dim Occurrences As Integer
Occurrances = InStrCount(input.ToLower, phrase.ToLower)
Note the use of .ToLower, which is used to ignore case in your comparison. Do not include this directive if you do wish comparison to be case specific.
One more solution based on InStr(i, str, substr) function (searching substr in str starting from i position, more info about InStr()):
Function findOccurancesCount(baseString, subString)
occurancesCount = 0
i = 1
Do
foundPosition = InStr(i, baseString, subString) 'searching from i position
If foundPosition > 0 Then 'substring is found at foundPosition index
occurancesCount = occurancesCount + 1 'count this occurance
i = foundPosition + 1 'searching from i+1 on the next cycle
End If
Loop While foundPosition <> 0
findOccurancesCount = occurancesCount
End Function
As soon as there is no substring found (InStr returns 0, instead of found substring position in base string), searching is over and occurances count is returned.
Looking at your original attempt, I have found that this should do the trick as "Split" creates an array.
Occurrences = input.split(phrase).ubound
This is CaSe sensitive, so in your case the phrase should equal "Hello there", as there is no "hello there" in the input
Expanding on Sumit Kumar's simple solution, here it is as a one-line working function:
Public Function fnStrCnt(ByVal str As String, ByVal substr As String) As Integer
fnStrCnt = UBound(Split(LCase(str), substr))
End Function
Demo:
Sub testit()
Dim thePhrase
thePhrase = "Once upon a midnight dreary while a man was in a house in the usa."
If fnStrCnt(thePhrase, " a ") > 1 Then
MsgBox "Found " & fnStrCnt(thePhrase, " a ") & " occurrences."
End If
End Sub 'testit()
I don't know if this is more obvious?
Starting from the beginning of longString check the next characters up to the number characters in phrase, if phrase is not found start looking from the second character etc. If it is found start agin from the current position plus the number of characters in phrase and increment the value of occurences
Module Module1
Sub Main()
Dim longString As String = "Hello there. My name is John. I work very hard. Hello there! Hello therehello there"
Dim phrase As String = "hello There"
Dim occurences As Integer = 0
Dim n As Integer = 0
Do Until n >= longString.Length - (phrase.Length - 1)
If longString.ToLower.Substring(n, phrase.Length).Contains(phrase.ToLower) Then
occurences += 1
n = n + (phrase.Length - 1)
End If
n += 1
Loop
Console.WriteLine(occurences)
End Sub
End Module
I used this in Vbscript, You can convert the same to VB.net as well
Dim str, strToFind
str = "sdfsdf:sdsdgs::"
strToFind = ":"
MsgBox GetNoOfOccurranceOf( strToFind, str)
Function GetNoOfOccurranceOf(ByVal subStringToFind As String, ByVal strReference As String)
Dim iTotalLength, newString, iTotalOccCount
iTotalLength = Len(strReference)
newString = Replace(strReference, subStringToFind, "")
iTotalOccCount = iTotalLength - Len(newString)
GetNoOfOccurranceOf = iTotalOccCount
End Function
I know this thread is really old, but I got another solution too:
Function countOccurencesOf(needle As String, s As String)
Dim count As Integer = 0
For i As Integer = 0 to s.Length - 1
If s.Substring(i).Startswith(needle) Then
count = count + 1
End If
Next
Return count
End Function

Excel UDF for capturing numbers within characters

I have a variable text field sitting in cell A1 which contains the following:
Text;#Number;#Text;#Number
This format can keep repeating, but the pattern is always Text;#Number.
The numbers can vary from 1 digit to n digits (limit 7)
Example:
Original Value
MyName;#123;#YourName;#3456;#HisName;#78
Required value:
123, 3456, 78
The field is too variable for excel formulas from my understanding.
I tried using regexp but I am a beginner when it comes to coding. if you can break down the code with some explanation text, it would be much appreciated.
I have tried some of the suggestions below and they work perfectly. One more question.
Now that I can split the numbers from the text, is there any way to utilize the code below and add another layer, where we split the numbers into x cells.
For example: once we run the function, if we get 1234, 567 in the same cell, the function would put 1234 in cell B2, and 567 in cell C2. This would keep updating all cells in the same row until the string has exhausted all of the numbers that are retrieved from the function.
Thanks
This is the John Coleman's suggested method:
Public Function GetTheNumbers(st As String) As String
ary = Split(st, ";#")
GetTheNumbers = ""
For Each a In ary
If IsNumeric(a) Then
If GetTheNumbers = "" Then
GetTheNumbers = a
Else
GetTheNumbers = GetTheNumbers & ", " & a
End If
End If
Next a
End Function
If the pattern is fixed, and the location of the numbers never changes, you can assume the numbers will be located in the even places in the string. This means that in the array result of a split on the source string, you can use the odd indexes of the resulting array. For example in this string "Text;#Number;#Text;#Number" array indexes 1, 3 would be the numbers ("Text(0);#Number(1);#Text(2);#Number(3)"). I think this method is easier and safer to use if the pattern is indeed fixed, as it avoids the need to verify data types.
Public Function GetNums(src As String) As String
Dim arr
Dim i As Integer
Dim result As String
arr = Split(src, ";#") ' Split the string to an array.
result = ""
For i = 1 To UBound(arr) Step 2 ' Loop through the array, starting with the second item, and skipping one item (using Step 2).
result = result & arr(i) & ", "
Next
If Len(result) > 2 Then
GetNums = Left(result, Len(result) - 2) ' Remove the extra ", " at the end of the the result string.
Else
GetNums = ""
End If
End Function
The numbers can vary from 1 digit to n digits (limit 7)
None of the other responses seems to take the provided parameters into consideration so I kludged together a true regex solution.
Option Explicit
Option Base 0 '<~~this is the default but I've included it because it has to be 0
Function numsOnly(str As String, _
Optional delim As String = ", ")
Dim n As Long, nums() As Variant
Static rgx As Object, cmat As Object
'with rgx as static, it only has to be created once; beneficial when filling a long column with this UDF
If rgx Is Nothing Then
Set rgx = CreateObject("VBScript.RegExp")
End If
numsOnly = vbNullString
With rgx
.Global = True
.MultiLine = False
.Pattern = "[0-9]{1,7}"
If .Test(str) Then
Set cmat = .Execute(str)
'resize the nums array to accept the matches
ReDim nums(cmat.Count - 1)
'populate the nums array with the matches
For n = LBound(nums) To UBound(nums)
nums(n) = cmat.Item(n)
Next n
'convert the nums array to a delimited string
numsOnly = Join(nums, delim)
End If
End With
End Function
      
Regexp option that uses Replace
Sub Test()
Debug.Print StrOut("MyName;#123;#YourName;#3456;#HisName;#78")
End Sub
function
Option Explicit
Function StrOut(strIn As String) As String
Dim objRegex As Object
Set objRegex = CreateObject("vbscript.regexp")
With objRegex
.Pattern = "(^|.+?)(\d{1,7})"
.Global = True
If .Test(strIn) Then
StrOut = .Replace(strIn, "$2, ")
StrOut = Left$(StrOut, Len(StrOut) - 2)
Else
StrOut = "Nothing"
End If
End With
End Function

Want to replace one character at specific position in VB 6.0

wordString --> Word for fill in the blank.
key-->Character is replaced.
I have also have the position of the key in keyPos which is calculated randomly
I'm making a fill in the blanks game. Here I need to create blanks at random position. I'm using Replace(wordString, key, "_", , 1)
But this only replace the first occurrence. If my wordString has repeating letters like APPLE it will always replace the first P
I want to replace the second P also. Like AP_LE.
I got another solution myself.
It has 3 text boxes txtInput, txtOutput, txtKeyPos and a command button command1
Code:
Private Sub Command1_Click()
t1 = Left$(txtInput.Text, Int(txtKeyPos.Text) - 1)
t2 = Right$(txtInput.Text, (Len(txtInput.Text)) - Int(txtKeyPos.Text))
txtOutput.Text = t1 & "_" & t2
End Sub
This serves my purpose.
OK this is vb.net and not vb6 but here goes::
You should do a word approach instead of a character approach:
Dim sentence as String = "My apple is red."
Dim wordsInSentence() as String = sentence.Split()
Dim Rnd as new Random
Dim wordToBlank as String = wordsInSentence(Rnd.next(0, wordsInSentence.length))
Dim blankedSentence as String = sentence.Replace(wordToBlank, "___")
And blankedSentence will contain your sentence with a random word blanked.
My ___ is red.
EDIT: To instead blank a random character in your string, randomise a character index in your string and (if it's not a space) blank that :
Dim sentence as String = "My apple is red."
Dim Rnd as new Random
Dim index As single = Rnd.next(0, sentence.length)
While sentence.Substring(index,1) = " "
index = Rnd.next(0, sentence.length)
End While
Dim blankedSentence as String = sentence.Remove(index,1).Insert(index, "_")
And blankedSentence contains your sentence with a random non-space letter blanked:
My ap_le is red.
This isn't a very good approach though as all letters of all words, including punctuation, can be the character that is blanked. Other than that it will get you what you wanted.
VB6 version:
Dim sentence as String
Dim index As Integer
Dim intUpperBound As Integer
Dim intLowerBound As Integer
sentence = "My apple is red."
intLowerBound = 1 'assuming the first character of the word
intUpperBound = Len(sentence)
Randomize 'initialize the random number generator
index = Int((intUpperBound - intLowerBound + 1) * Rnd) + intLowerBound
While Mid$(sentence, index, 1) = " "
index = Int((intUpperBound - intLowerBound + 1) * Rnd) + intLowerBound
Wend
Dim blankedSentence As String
blankedSentence = sentence
Mid(blankedSentence, index, 1) = "_" 'replace the current character at index with the new character

Split comma delimited string to array using regex

I have a string as below, which needs to be split to an array, using VB.NET
10,"Test, t1",10.1,,,"123"
The result array must have 6 rows as below
10
Test, t1
10.1
(empty)
(empty)
123
So:
1. quotes around strings must be removed
2. comma can be inside strings, and will remain there (row 2 in result array)
3. can have empty fields (comma after comma in source string, with nothing in between)
Thanks
Don't use String.Split(): it's slow, and doesn't account for a number of possible edge cases.
Don't use RegEx. RegEx can be shoe-horned to do this accurately, but to correctly account for all the cases the expression tends to be very complicated, hard to maintain, and at this point isn't much faster than the .Split() option.
Do use a dedicated CSV parser. Options include the Microsoft.VisualBasic.TextFieldParser type, FastCSV, linq-to-csv, and a parser I wrote for another answer.
You can write a function yourself. This should do the trick:
Dim values as New List(Of String)
Dim currentValueIsString as Boolean
Dim valueSeparator as Char = ","c
Dim currentValue as String = String.Empty
For Each c as Char in inputString
If c = """"c Then
If currentValueIsString Then
currentValueIsString = False
Else
currentValueIsString = True
End If
End If
If c = valueSeparator Andalso not currentValueIsString Then
If String.IsNullOrEmpty(currentValue) Then currentValue = "(empty)"
values.Add(currentValue)
currentValue = String.Empty
End If
currentValue += c
Next
Here's another simple way that loops by the delimiter instead of by character:
Public Function Parser(ByVal ParseString As String) As List(Of String)
Dim Trimmer() As Char = {Chr(34), Chr(44)}
Parser = New List(Of String)
While ParseString.Length > 1
Dim TempString As String = ""
If ParseString.StartsWith(Trimmer(0)) Then
ParseString = ParseString.TrimStart(Trimmer)
Parser.Add(ParseString.Substring(0, ParseString.IndexOf(Trimmer(0))))
ParseString = ParseString.Substring(Parser.Last.Length)
ParseString = ParseString.TrimStart(Trimmer)
ElseIf ParseString.StartsWith(Trimmer(1)) Then
Parser.Add("")
ParseString = ParseString.Substring(1)
Else
Parser.Add(ParseString.Substring(0, ParseString.IndexOf(Trimmer(1))))
ParseString = ParseString.Substring(ParseString.IndexOf(Trimmer(1)) + 1)
End If
End While
End Function
This returns a list. If you must have an array just use the ToArray method when you call the function
Why not just use the split method?
Dim s as String = "10,\"Test, t1\",10.1,,,\"123\""
s = s.Replace("\"","")
Dim arr as String[] = s.Split(',')
My VB is rusty so consider this pseudo-code

replace space in a string at random position in vb.net

I want to select a random space in a string and replace it with a word (%word%) but there is a problem. The position cannot be fixed as i want it to be inserted at a random break. Few things which iam considering :
1)break the string at a space and merge it with the word
2) find a random space and replace it with the word. I like this point and so far all i have is break the selectedtext into string array and then iterate over each line. But i don't know how to find a random string position? Any short and sweet code please?
If (rtfArticle.SelectedText.Length > 0) Then
Dim strArray As String() = rtfArticle.SelectedText.Split(New Char() {ChrW(10)})
For Each str3 As String In strArray
If (str3.Contains(" ") = True) Then
End If
Next
End If
You could use the Random class to generate a random position index.
Dim testString = "This is just a test for random position"
Dim random = New Random()
Dim randomPos = random.Next(0, testString.Length - 1)
Debug.Print(String.Format("Char at Pos {0} = {1}", randomPos, testString.ElementAt(randomPos)))
You could locate the spaces in the string, pick one by random, and replace it. Something like:
' Get string
Dim data As String = rtfArticle.SelectedText
' Get space positions
Dim spaces As New List(Of Integer)
For i As Integer = 0 to data.Length - 1
If data(i) = " "C Then spaces.Add(i)
Next
' Get a random space
Dim rnd As New Random()
Dim pos As Integer = spaces(rnd.Next(spaces.Length))
' Remove the space
data = data.Remove(pos, 1)
' Insert the replacement
data = data.Insert(pos, "%word%")
' Put the string back
rtfArticle.SelectedText = data