Get/split text inside brackets/parentheses - regex

Just have a list of words, such as:
gram (g)
kilogram (kg)
pound (lb)
just wondering how I would get the words within the brackets for example get the "g" in "gram (g)" and dim it as a new string.
Possibly using regex?
Thanks.

Use split function ..
strArr = str.Split("(") ' splitting 'gram (g)' returns an array ["gram " , "g)"] index 0 and 1
strArr2 = strArr[1].Split(")") ' splitting 'g)' returns an array ["g " ..]
the string is in
strArr2[0]
Edit
you want getAbbrev and getAbbrev2 to be arrays
try
Dim getAbbrev As String() = Str.Split("(")
Dim getAbbrev2 as String() = getAbbrev[1].Split(")")
To do it without declaring arrays you can do
"gram (g)".Split("(")[1].Split(")")[0]
but that's unreadable
Edit
You have some very trivial errors. I would suggest you strengthen your understanding on objects and declarations first. Then you can look into invoking methods. I rather have you understand it than give it to you. Re-read the book you have or look for a basic tutorial.
Dim unit As String = 'make sure this is the actual string you are getting, not sure where you are supposed to get the string value from => ie grams (g)
Dim getAbbrev As String() = unit.Split("(") 'use unit not Str - Str does not exist
Dim getAbbrev2 As String() = getAbbrev[1].Split(")") 'As no as - case sensitive
for the last line reference getAbbrev2 instead of the unknown abbrev2

Fun with Regular Expressions (I'm really not an expert here, but tested and works)
Imports System.Text.RegularExpressions
.....
Dim charsToTrim() As Char = { "("c, ")"c }
Dim test as String = "gram (g)" + Environment.NewLine +
"kilogram (kg)" + Environment.NewLine +
"pound (lb)"
Dim pattern as String = "\([a-zA-Z0-9]*\)"
Dim r As Regex = new Regex(pattern, RegexOptions.IgnoreCase)
Dim m As Match = r.Match(test)
While(m.Success)
System.Diagnostics.Debug.WriteLine("Match" + "=" + m.Value.ToString())
Dim tempText as String = m.Value.ToString().Trim(charsToTrim)
System.Diagnostics.Debug.WriteLine("String Trimmed" + "=" + tempText)
m = m.NextMatch()
End While

You can split at the space and remove the parens from the second token (by replacing them with an empty string).
A regex is also an option, and is very simple, its pattern is
\w+\s+\((\w+)\)
Which means, a word, then at least one space, then opening parens, then in real regex parens you search for a word, and, eventually a closing paren. The inner parentheses are capturing parentheses, which make it possible to refer to the unit g, kg, lb.

Related

vb.net identify keyword in simple lexical analyser

I have a vb.net regex which I am using to identify operators in a simple z + x sum. How can I identify keywords in the given expression with the use of lexical analysis?
My current code:
Dim input As String = txtInput.Text
Dim symbol As String = "([-+*/])"
Dim substrings() As String = Regex.Split(input, symbol)
For Each match As String In substrings
lstOutput.Items.Add(match) '<-- Do I need to add a string here to identify the regular expression?
Next
input: z + x
This is what I want to happen in the output
z - keyword
+ - operator
x - keyword
Consider the following update to your code (as a Console project):
operators contains a string that you can include in your Regex pattern and also refer to later
in the loop, check if operators contains match meaning that the match is an operator
anything else is a keyword
So here's the code:
Dim input As String = "z+x"
Dim operators As String = "-+*/"
Dim pattern As String = "([" & operators & "])"
Dim substrings() As String = Regex.Split(input, pattern)
For Each match As String In substrings
If operators.Contains(match) Then
Console.WriteLine(match & " - operator")
Else
Console.WriteLine(match & " - keyword")
End if
Next

VB.NET Modify Matching with Access Database

i'm working in a dictionary program
as example if i want to get this line from database:
i suppose to write this in english textbox:
but if i wrote it like this:
no match is found while it is the same no comma
or any other modification except the new line
i failed to modify the code to make the program match a sentence
of words regardless of new line in between
the code of the translation function:
Function getexactsubtitles(ByVal content As String) As String
Try
Dim count As Integer = 0
Dim connectionall As New OleDb.OleDbConnection(connectionString)
Using adp As New OleDbDataAdapter
Using tbl As New DataTable
Using cmd As OleDbCommand = New OleDbCommand("SELECT * FROM [Subtitles]", connectionall)
cmd.Parameters.AddWithValue("#english", String.Concat("%", content, "%"))
adp.SelectCommand = cmd
If adp.Fill(tbl) > 0 Then
For Each row As DataRow In tbl.Rows
Dim en As String = row.Item("English").Replace("?", "\?")
Dim ar As String = row.Item("Arabic")
count += Regex.Matches(content, en, RegexOptions.IgnoreCase).Count
content = Regex.Replace(content, en, ar, RegexOptions.IgnoreCase)
Next
End If
End Using
End Using
End Using
MsgBox(IIf(count = 0, "لم يتم العثور على أى تطابق تام داخل قاعدة البيانات", "عدد الحالات المطابقة تماماً التى عثر عليها داخل قاعدة البيانات (" & " " & count & " " & ") من الجمل والكلمات"))
Return content
Catch ex As Exception
MsgBox(ex.Message)
End Try
getexactsubtitles = ""
End Function
please notice this part:
Using cmd As OleDbCommand = New OleDbCommand("SELECT * FROM [Subtitles]", connectionall)
cmd.Parameters.AddWithValue("#english", String.Concat("%", content, "%"))
this is my try to do the job but for some reason it is not working
code for translation button:
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
TextBox2.Text = getexactsubtitles(TextBox1.Text)
If I understand correctly, you are using Regex.Replace() and the pattern is stored in the first column of a table.
And all you need is for " " to also match newlines.
I think you should consider replacing " " with \s+ in your pattern, since it matches any of these characters: [\r\n\t\f ]. More examples
The "+" in \s+ is to repeat one or more times. That way, it can match
How are you [space] + [cr] + [lf]
today tommy?
Solution
In the example you provided,
[English] | [Arabic]
how\s+are\s+you\s+today\s+tommy\? | asking about tommy's health
Aternative: if you can't store that pattern in the database, replace it in your code (this is not quite efficient)
Dim en As String = row.Item("English").Replace("?", "\?").Replace(" ","\s+")
Also, I noticed you are escaping the question marks. You should also be aware there might be some other metacharacters. So please consider using Regex.Escape() instead.

Searching multiple .txt files for all occurrences of a string?

I am trying to create a tool that will search 300+ .txt files for a string that that may be used several times in each of the 300+ .txt files
I want to be able to go through each file and get the string between each of the occurrences.
It sounds a bit twisted I know, I have been scratching my head for hours, while testing code.
What I have tried
I read through each file and check for if it contains my search text at least once, if it does, then I add the full path of the (files that do contain it) to a list
Dim FileNamesList As New List(Of String)
Dim occurList As New List(Of String)
Dim textSearch As String = TextBox1.Text.ToLower
'check each file to see if it even contains textbox1.text
'if it does, then add matching files to list
For Each f As FileInfo In dir.GetFiles("*.txt")
Dim tmpRead = File.ReadAllText(f.FullName).ToLower
Dim tIndex As Integer = tmpRead.IndexOf(textSearch)
If tIndex > -1 Then
FileNamesList.Add(f.FullName)
End If
Next
Then I thought, oh, now all I need to do is go through each string in that 'approved' files list and add the entire contents of each to a new list.
Then I go through each in 'that' list and get string between two delimiters.
And... I just get lost from there...
Here is the get string between delimiters I have tried using.
Private Function GetStringBetweenTags(ByVal startIdentifer As String, ByVal endIndentifier As String, ByVal textsource As String) As String
Dim idLength As Int16 = startIdentifer.Length
Dim s As String = textsource
Try
s = s.Substring(s.IndexOf(startIdentifer) + idLength)
s = s.Substring(0, s.IndexOf(endIndentifier))
'MsgBox(s)
Catch
End Try
Return s
End Function
In simple terms...
I have 300 .txt files
Some may contain a string that I am after
I want the substring of each string
Normally I am fine, and never need to ask questions, but there is too many forceptions going on.
Logical Example
== Table.txt ==
print("I am tony")
print("pineapple")
print("brown cows")
log("cable ties")
log("bad ocd")
log("bingo")
== Cherry.txt ==
print("grapes")
print("pie")
print("apples")
log("laugh")
log("tuna")
log("gonuts")
== Tower.txt ==
print("tall")
print("clouds")
print("nomountain")
log("goggles?")
log("kuwait")
log("india")
I want to end with list of the text between only the print function from all 3 files
Haven't found any other thread about this, probably because it stupid.
So I should end with
== ResultList ==
I am tony
pineapple
brown cows
grapes
pie
apples
tall
clouds
nomountain
RegEx is probably your best choice for something like this. For instance:
Dim results As New List(Of String)()
Dim r As New RegEx("print\(""(.*)""\)")
For path As String In filePaths
Dim contents As String = File.ReadAllText(path)
For Each m As Match in r.Matches(contents)
If m.Sucess Then
results.Add(m.Groups(1).Value)
End If
Next
Next
As you can see, the code loops through a list of file paths. For each one, it loads the entire contents of the file into a string. It then searches the file contents string for all matches to the following regular expression pattern: print\("(.*)"\). It then loops through all of those pattern matches and grabs the value of the first capture group from each one. Those are added to the results list, which contains your desired strings. Here's the meaning of the parts of the RegEx:
print - Looks for any string starting with the word "print"
\( - The next character after the word "print" must be an open parentheses (the backslash is an escape character)
" - The next character after the open parentheses must be a double quote character (it is repeated twice so as to escape it so that VB doesn't think it's the end of the string).
(.*) - The parentheses define this as a capturing group (so that we can pull out just this value from the matches). The .* means any characters of any length.
"\) - Matching strings must end with a double quote followed by a closing parentheses.
Use Regex:
Imports System.Text.RegularExpressions
Module Module1
Sub Main()
Dim input1 As String = _
"print(""I am tony"") " + _
"print(""pineapple"") " + _
"print(""brown cows"") " + _
"log(""cable ties"") " + _
"log(""bad ocd"") " + _
"log(""bingo"")"
Dim input2 As String = _
"print(""grapes"") " + _
"print(""pie"") " + _
"print(""apples"") " + _
"log(""laugh"") " + _
"log(""tuna"") " + _
"log(""gonuts"")"
Dim input3 As String = _
"print(""tall"") " + _
"print(""clouds"") " + _
"print(""nomountain"") " + _
"log(""goggles?"") " + _
"log(""kuwait"") " + _
"log(""india"")"
Dim pattern As String = "print\(""([^""]*)""\)"
Dim expr As Regex = New Regex(pattern, RegexOptions.Singleline)
Dim matches As MatchCollection = Nothing
Dim data As List(Of String) = New List(Of String)()
matches = expr.Matches(input1)
For Each mat As Match In matches
data.Add(mat.Groups(1).Value)
Next mat
matches = expr.Matches(input2)
For Each mat As Match In matches
data.Add(mat.Groups(1).Value)
Next mat
matches = expr.Matches(input3)
For Each mat As Match In matches
data.Add(mat.Groups(1).Value)
Next mat
End Sub
End Module

Use Regex to update VBA code

I have a VBA source code containing many hard coded references to cells. The code is part of the Worksheet_Change sub, so I guess hard coding the range references was necessary and you will see many assignment statements like the following:
Set cell = Range("B7")
If Not Application.Intersect(cell, Range(Target.Address)) Is Nothing Then
I would like insert 2 additional rows on top of the worksheet, so basically all the row references will shift by 2 rows. So for example the above assignment statement will be changed to Set cell = Range("B9").
Given the large number of hard coded row references in the code, I thought of using Regex to increment all the row references by 2. So I have developed the following code.
Sub UpdateVBACode()
'*********************Read Text File Containing VBA code and assign content to string variable*************************
Dim str As String
Dim strFile As String: strFile = "F:\Preprocessed_code.txt"
Open strFile For Input As #1
str = Input$(LOF(1), 1)
Close #1
'*********************Split string variables to lines******************************************************************
Dim vStr As Variant: vStr = Split(str, vbCrLf)
'*********************Regex work***************************************************************************************
Dim rex As New RegExp
rex.Global = True
Dim i As Long
Dim mtch As Object
rex.Pattern = "(""\w)([0-9][0-9])("")" ' 3 capturing groups to reconstruct the replacement string
For i = 0 To UBound(vStr, 1)
If rex.Test(vStr(i)) Then
For Each mtch In rex.Execute(vStr(i))
vStr(i) = rex.Replace(vStr(i), mtch.SubMatches(0) & IncrementString(mtch.SubMatches(1)) & mtch.SubMatches(2))
Next
End If
Next i
'********************Reconstruct String*********************************************************************************
str = ""
For i = 0 To UBound(vStr, 1)
str = str & vbCrLf & vStr(i)
Next i
'********************Write string to text file******************************************************************************
Dim myFile As String
myFile = "F:\Processed_code.txt"
Open myFile For Output As #2
Print #2, str
Close #2
'
End Sub
Function IncrementString(rowNum As String) As String '
Dim num As Integer
num = CInt(rowNum) + 2
IncrementString = CStr(num)
End Function
The above VBA code works, except it fails if there are two row references in the same line, so for instance if we have If Range("B15").Value <> Range("B12").Value Then, after the line gets processed I get If Range("B14").Value <> Range("B14").Value Theninstead of If Range("B17").Value <> Range("B14").Value Then. The problem is in the vStr(i) = rex.Replace(vStr(i), mtch.SubMatches(0) & IncrementString(mtch.SubMatches(1)) & mtch.SubMatches(2)) statement, because it is getting called more than once if a line has more than Regex match.
Any ideas? Thanks in advance
I think what you are trying to do is a bad idea, for two reasons:
Hard-coded cell references are almost always poor practice. A better solution may be to replace hard-coded cell references with named ranges. You can refer to them in the code by name, and the associated references will update automatically if you insert/delete rows or columns. You have some painful upfront work to do but the result will be a much more maintainable spreadsheet.
You are effectively trying to write a VBA parser using regexes. This is pretty much guaranteed not to work in all cases. Your current regex will match lots of things that aren't cell references (e.g. "123", "_12", and "A00") and will also miss lots of hard-coded cell references (e.g. "A1" and Cell(3,7)). That may not matter for your particular code but the only way to be sure it's worked is to check each reference by hand. Which is IMHO not much less effort than refactoring (e.g. replace with named ranges). In my experience you don't fix a regex, you just make the problems more subtle.
That said, since you asked...
<cthulu>
There are only two choices when using RegExp.Replace() - either replace the first match or replace all matches (corresponding to setting RegExp.Global to False or True respectively). You don't have any finer control than that, so your logic has to change. Instead of using Replace() you could write your own code for the replacements, using the FirstIndex property of the Match object, and VBA's string functions to isolate the relevant parts of the string:
Dim rex As Object
Set rex = CreateObject("VBScript.RegExp")
rex.Global = True
Dim i As Long
Dim mtch As Object
Dim newLineText As String
Dim currMatchIndex As Long, prevPosition As Long
rex.Pattern = "(""\w)([0-9][0-9])("")" ' 3 capturing groups to reconstruct the replacement string
For i = 0 To UBound(vStr, 1)
If rex.Test(vStr(i)) Then
currMatchIndex = 0: prevPosition = 1
newLineText = ""
For Each mtch In rex.Execute(vStr(i))
'Note that VBA string functions are indexed from 1 but Match.FirstIndex starts from 0
currMatchIndex = mtch.FirstIndex
newLineText = newLineText & Mid(vStr(i), prevPosition, currMatchIndex - prevPosition + 1) & _
mtch.SubMatches(0) & IncrementString(mtch.SubMatches(1)) & mtch.SubMatches(2)
prevPosition = currMatchIndex + Len(mtch.Value) + 1
Next
vStr(i) = newLineText & Right(vStr(i), Len(vStr(i)) - prevPosition + 1)
End If
Next i
Note that I still haven't fixed the problems with the regex pattern in the first place. I recommend that you just go and use named ranges instead...
Oops, nearly forgot - </cth

regex not matching correctly

First of all, I would like an opinion if using regex is even the best solution here, I'm fairly new to this area and regex is the first thing I found and it seemed somewhat easy to use, until I need to grab a long section of text out of a line lol. I'm using a vb.net environment for regex.
Basically, I'm taking this line here:
21:24:55 "READ/WRITE: ['PASS',false,'27880739',[40,[459.313,2434.11,0.00221252]],[["ItemFlashlight","ItemWatch","ItemMap","ItemKnife","ItemEtool","ItemGPS","ItemHatchet","ItemCompass","ItemMatchbox","M9SD","ItemFlashlightRed","NVGoggles","Binocular_Vector","ItemToolbox","M4A1_AIM_SD_camo"],["ItemPainkiller","ItemMorphine","ItemSodaPepsi","FoodSteakCooked",["30Rnd_556x45_StanagSD",29],"30Rnd_556x45_StanagSD","30Rnd_556x45_StanagSD","30Rnd_556x45_StanagSD","30Rnd_556x45_StanagSD","30Rnd_556x45_StanagSD",["15Rnd_9x19_M9SD",12],["15Rnd_9x19_M9SD",10],"15Rnd_9x19_M9SD","15Rnd_9x19_M9SD","ItemBandage"]],["DZ_Backpack_EP1",[["BAF_AS50_TWS"],[1]],[["FoodSteakCooked","ItemPainkiller","ItemMorphine","ItemSodaCoke","5Rnd_127x99_as50","ItemBloodbag"],[2,1,1,2,4,1]]],[316,517,517],Sniper1_DZ,0.94]"
Using the following regex:
\[\[([\w|_|\""|,]*)\],\[([\w|_|\""|,|\[|\]]*)\]\],
To try and get the following:
[["ItemFlashlight","ItemWatch","ItemMap","ItemKnife","ItemEtool","ItemGPS","ItemHatchet","ItemCompass","ItemMatchbox","M9SD","ItemFlashlightRed","NVGoggles","Binocular_Vector","ItemToolbox","M4A1_AIM_SD_camo"],["ItemPainkiller","ItemMorphine","ItemSodaPepsi","FoodSteakCooked",["30Rnd_556x45_StanagSD",29],"30Rnd_556x45_StanagSD","30Rnd_556x45_StanagSD","30Rnd_556x45_StanagSD","30Rnd_556x45_StanagSD","30Rnd_556x45_StanagSD",["15Rnd_9x19_M9SD",12],["15Rnd_9x19_M9SD",10],"15Rnd_9x19_M9SD","15Rnd_9x19_M9SD","ItemBandage"]]
However either my regex is flawed, or my vb.net code is. It only displays the following data:
[["ItemFlashlight","ItemWatch","ItemMap","ItemKnife","ItemEtool","ItemGPS","ItemHatchet","ItemCompass","ItemMatchbox","M9SD","ItemFlashlightRed","NVGoggles","Binocular_Vector","ItemToolbox","M4A1_AIM_SD_camo"],["ItemPainkiller","ItemMorphine","ItemSodaPepsi",
My vb.net code in case you need to peek at it is:
ListView1.Clear()
Call initList(Me.ListView1)
My.Computer.FileSystem.CurrentDirectory = My.Settings.cfgPath
My.Computer.FileSystem.CopyFile("arma2oaserver.RPT", "tempRPT.txt")
Dim ScriptLine As String = ""
Dim path As String = My.Computer.FileSystem.CurrentDirectory & "\tempRPT.txt"
Dim lines As String() = IO.File.ReadAllLines(path, System.Text.Encoding.Default)
Dim que = New Queue(Of String)(lines)
ProgressBar1.Maximum = lines.Count + 1
ProgressBar1.Value = 0
Do While que.Count > 0
ScriptLine = que.Dequeue()
ScriptLine = LCase(ScriptLine)
If InStr(ScriptLine, "login attempt:") Then
Dim rtime As Match = Regex.Match(ScriptLine, ("(\d{1,2}:\d{2}:\d{2})"))
Dim nam As Match = Regex.Match(ScriptLine, "\""([^)]*)\""")
Dim name As String = nam.ToString.Replace("""", "")
Dim next_line As String = que.Peek 'Read next line temporarily 'This is where it would move to next line temporarily to read from it
next_line = LCase(next_line)
If InStr(next_line, "read/write:") > 0 Then 'Or InStr(next_line, "update: [b") > 0 Then 'And InStr(next_line, "setmarkerposlocal.sqf") < 1 Then
Dim coords As Match = Regex.Match(next_line, "\[(\d+)\,\[(-?\d+)\.\d+\,(-?\d+)\.\d+,([\d|.|-]+)\]\]")
Dim inv As Match = Regex.Match(next_line, "\[\[([\w|_|\""|,]*)\],\[([\w|_|\""|,|\[|\]]*)\]\],") '\[\[([\w|_|\""|,]*)\],\[([\w|_|\""|,|\[|\]]*)\]\],
'\[\[([\w|_|\""|,]*)\],\[([\w|_|\""|,|\[|\]]*)\]\]:\[([\w|_|\""|,|\[|\]]*)\]\:
Dim back As Match = Regex.Match(next_line, "\""([\w|_]+)\"",\[\[([\w|_|\""|,]*)\],\[([\d|,]*)\]\],\[\[([\w|_|\""|,]*)\],\[([\d|,]*)\]\]")
Dim held As Match = Regex.Match(next_line, "\[\""([\w|_|\""|,]+)\""\,\d+\]")
With Me.ListView1
.Items.Add(name.ToString)
With .Items(.Items.Count - 1).SubItems
.Add(rtime.ToString)
.Add(coords.ToString)
.Add(inv.ToString)
.Add(back.ToString)
.Add(held.ToString)
End With
End With
End If
End If
ProgressBar1.Value += 1
Loop
My.Computer.FileSystem.DeleteFile("tempRPT.txt")
ProgressBar1.Value = 0
The odd thing is, when I test my regex in Expresso it gets the full, correct match. So I don't know what I'm doing wrong.
I'm not sure what's wrong with the regex you have, but the first match off of this one seems to work fine:
\[\[.*?\]\]
Hope this helps.
-EDIT-
The problem isn't the regex, it's that ListView is truncating the display of the string. See here
Try this regular expression instead: \Q[[\E(?:(?!\Q[[\E).)+]]
http://regex101.com/r/zP1aC5
If you need a backref, use \Q[[\E((?:(?!\Q[[\E).)+)]]
Perhaps you should specify whether you are working with single line or multi line input text. Depending on your input text format, try with:
Dim variableName as Match = Regex.Match("input", "pattern", RegexOptions.SingleLine);
or
Dim variableName as Match = Regex.Match("input", "pattern", RegexOptions.Multiline);