Extract numeric info from text - regex

I need to extract numeric info from text.
Ready
State: CTYG Work Request #: 2880087 General
Job Address
Contact
Work Request Search
My code :
$Text = WinGetText("[ACTIVE]")
Sleep(4000)
$Value = StringSplit($Text, #CRLF)
MsgBox(0, "Hello", $Value, 10) ;---1st message box
Sleep(4000)
For $i = 1 To $Value[0]
If StringRegExp($Value[$i], "[0-9][^:alpha:]") Then
MsgBox(0, "Hello1", $Value[$i], 5) ;---2nd message box
Sleep(200)
$newWR = $Value[$i]
MsgBox(0, "Hello2", $newWR, 10)
ConsoleWrite($newWR) ;---3rd message box
EndIf
Next
1st MsgBox() shows nothing. The 2nd and 3rd show State: CTYG Work Request #: 2880087 General. But I don't need the entire line, I just want 2880087.

What about this? This will delete everything but numbers.
$str = "State: CTYG Work Request #: 2880087 General"
ConsoleWrite(StringRegExpReplace($str, '\D', '') & #CRLF)

… i just want 2880087 …
Example using regular expression State: .+ #: (\d+) :
#include <StringConstants.au3>; StringRegExp()
#include <Array.au3>
Global Const $g_sText = 'Ready' & #CRLF & #CRLF _
& 'State: CTYG Work Request #: 2880087 General' & #CRLF & #CRLF _
& 'Job Address' & #CRLF & #CRLF _
& 'Contact' & #CRLF & #CRLF _
& 'Work Request Search'
Global Const $g_sRegEx = 'State: .+ #: (\d+)'
Global Const $g_aResult = StringRegExp($g_sText, $g_sRegEx, $STR_REGEXPARRAYMATCH)
ConsoleWrite($g_sText & #CRLF)
_ArrayDisplay($g_aResult)
Stores 2880087 to $g_aResult[0].

Related

Regex to replace word except in comments

How can I modify my regex so that it will ignore the comments in the pattern in a language that doesn't support lookbehind?
My regex pattern is:
\b{Word}\b(?=([^"\\]*(\\.|"([^"\\]*\\.)*[^"\\]*"))*[^"]*$)
\b{Word}\b : Whole word, {word} is replaced iteratively for the vocab list
(?=([^""\](\.|""([^""\]\.)[^""\]""))[^""]$) : Don't replace anything inside of quotes
My goal is to lint variables and words so that they always have the same case. However I do not want to lint any words in a comment. (The IDE sucks and there is no other option)
Comments in this language are prefixed by an apostrophe. Sample code follows
' This is a comment
This = "Is not" ' but this is
' This is a comment, what is it's value?
Object.value = 1234 ' Set value
value = 123
Basically I want the linter to take the above code and say for the word "value" update it to:
' This is a comment
This = "Is not" ' but this is
' This is a comment, what is it's value?
Object.Value = 1234 ' Set value
Value = 123
So that all code based "Value" are updated but not anything in double quotes or in a comment or part of another word such as valueadded wouldn't be touched.
I've tried several solutions but haven't been able to get it to work.
['.*] : Not preceeding an apostrophy
(?<!\s*') : BackSearch not with any spaces with apoostrophy
(?<!\s*') : Second example seemed incorrect but this won't work as the language doesn't support backsearches
Anybody have any ideas how I can alter my pattern so that I don't edit commented variables
VBA
Sub TestSO()
Dim Code As String
Dim Expected As String
Dim Actual As String
Dim Words As Variant
Code = "item = object.value ' Put item in value" & vbNewLine & _
"some.item <> some.otheritem" & vbNewLine & _
"' This is a comment, what is it's value?" & vbNewLine & _
"Object.value = 1234 ' Set value" & vbNewLine & _
"value = 123" & vbNewLine
Expected = "Item = object.Value ' Put item in value" & vbNewLine & _
"some.Item <> some.otheritem" & vbNewLine & _
"' This is a comment, what is it's value?" & vbNewLine & _
"Object.Value = 1234 ' Set value" & vbNewLine & _
"Value = 123" & vbNewLine
Words = Array("Item", "Value")
Actual = SOLint(Words, Code)
Debug.Print Actual = Expected
Debug.Print "CODE: " & vbNewLine & Code
Debug.Print "Actual: " & vbNewLine & Actual
Debug.Print "Expected: " & vbNewLine & Expected
End Sub
Public Function SOLint(ByVal Words As Variant, ByVal FileContents As String) As String
Const NotInQuotes As String = "(?=([^""\\]*(\\.|""([^""\\]*\\.)*[^""\\]*""))*[^""]*$)"
Dim RegExp As Object
Dim Regex As String
Dim Index As Variant
Set RegExp = CreateObject("VBScript.RegExp")
With RegExp
.Global = True
.IgnoreCase = True
End With
For Each Index In Words
Regex = "[('*)]\b" & Index & "\b" & NotInQuotes
RegExp.Pattern = Regex
FileContents = RegExp.Replace(FileContents, Index)
Next Index
SOLint = FileContents
End Function
As discussed in the comments above:
((?:\".*\")|(?:'.*))|\b(v)(alue)\b
3 Parts to this regex used with alternation.
A non-capturing group for text within double quotes, as we dont need that.
A non-capturing group for text starting with single quote
Finally the string "value" is split into two parts (v) and (value) because while replacing we can use \U($2) to convert v to V and rest as is so \E$3 where \U - converts to upper case and \E - turns off the case.
\b \b - word boundaries are used to avoid any stand-alone text which is not part of setting a value.
https://regex101.com/r/mD9JeR/8

Using vbscript regular expression to conditional replace dates

I would like to use regex to replace the actual dates in the string to YYYYMMDD. However, my string might contain 2 types of dates, it could either be 20160531 or 160531. For these two, I have to replace them with YYYYMMDD and YYMMDD. So the followings are two examples:
Employment_salary_20160531 -> Employment_salary_YYYYMMDD
Employment_salary_160531 -> Employment_salary_YYMMDD
Wondering if it is possible to do this within a single regex without using an IFELSE statement?
Thank you!
This will provide you with accurate validation of the date that's entered. The other regex will work but it's dirty. It will accept 5000 as year.
The short answer: ((19|20)\d{2}|[0-9]{2})(0[1-9]|1[0-2])([012][0-9]|3[0-1])
The Long but thoroughly tested answer...
stringtest1 = "Employment_salary_20160531"
stringtest2 = "Employment_salary_990212"
stringtest3 = "Employment_salary_990242"
wscript.echo : wscript.echo "---------------------------------------------------" : wscript.echo
wscript.echo "Trying: " & stringtest1 & vbcrlf & vbcrlf & vbtab & " => " & sanitizedate(stringtest1)
wscript.echo : wscript.echo "---------------------------------------------------" : wscript.echo
wscript.echo "Trying: " & stringtest2 & vbcrlf & vbcrlf & vbtab & " => " & sanitizedate(stringtest2)
wscript.echo : wscript.echo "---------------------------------------------------" : wscript.echo
wscript.echo "Trying: " & stringtest3 & vbcrlf & vbcrlf & vbtab & " => " & sanitizedate(stringtest3)
wscript.echo : wscript.echo "---------------------------------------------------" : wscript.echo
Function sanitizedate(str)
Set objRE = New RegExp
objRE.Pattern = "((19|20)\d{2}|[0-9]{2})(0[1-9]|1[0-2])([012][0-9]|3[0-1])"
objRE.IgnoreCase = True
objRE.Global = False
objRE.Multiline = true
Set objMatch = objRE.Execute(str)
If objMatch.Count = 1 Then
Select Case Len(objMatch.Item(0))
Case "8"
sanitizedate = Replace(str, objMatch.Item(0), "YYYYMMDD")
Case "6"
sanitizedate = Replace(str, objMatch.Item(0), "YYMMDD")
End Select
Else
sanitizedate = str
End if
End Function
Validation Results
Trying: Employment_salary_20160531
=> Employment_salary_YYYYMMDD
Trying: Employment_salary_990212
=> Employment_salary_YYMMDD
Trying: Employment_salary_990242 failed because 42 is not a valid date
=> Employment_salary_990242
I'm not sure I get you right. But seems there is two different replacement YYYYMMDD and YYMMDD which doing that is impossible by just one single pattern.
You can match those two separated pattern by this:
/(^(\d{4})(\d{2})(\d{2})$)|(^(\d{2})(\d{2})(\d{2})$)/
Online Demo
As you see, pattern above matches both 20160531 and 160531. But you cannot replace them with both YYYYMMDD (for 20160531) and YYMMDD (for 160531). You actually can replace them with either YYYYMMDD or YYMMDD.
Otherwise you need two separated patterns if you want two separated replacements:
/^(\d{4})(\d{2})(\d{2})$/
/* and replace with `YYYYMMDD` */
/^(\d{2})(\d{2})(\d{2})$/
/* and replace with YYMMDD */

Using replace with some kind of loop?

I have a variable with the following values:
Variable1 = "Apple, Banana, Pineaple, Grape, Coconut"
I would like to use the Replace to get the following result:
VariableX = "<span class="text1">Apple</span> <span class="text2">Banana</span> <span class="text1">Pineapple</span> <span class="text2">Grape</span> <span class="text1">Coconut</span>"
So, the first value gets text1, the second gets text2, the third gets text1, the forth gets text2 and so on, until the end.
' Split into an array...
a = Split(Variable1, ",")
' Add each element to a <span> tag...
For i = 0 To UBound(a)
VariableX = VariableX & "<span class=""text" & i + 1 & """>" & Trim(a(i)) & "</span>"
Next
Update with respect to comments:
To alternate between two values you can put them in an array and use Mod to alternatively select one of the values.
a = Split(Variable1, ",")
strClasses = Array("text-info", "text-warning")
' Add each element to a <span> tag...
For i = 0 To UBound(a)
VariableX = VariableX & "<span class=""" & strClasses(i Mod 2) & """>" & Trim(a(i)) & "</span>"
Next

Getting the group users in computer using AutoIt

I am trying to get all the group users in a computer. If I do this manually, my way is to go to Computer Management to get the list of Local Users and Group, and from there, I can get the list of Users and Group.
This is my code and I use AutoIt:
Func User()
Local $objWMIService, $colSettings, $objComputer, $strComputer = "."
;# Initiate the object
$objWMIService = ObjGet("winmgmts:{impersonationLevel=impersonate}!\\" & $strComputer & "\root\cimv2")
;# Check if it's an object
If IsObj($objWMIService) Then
;# Search for PC Infomration
$colSettings = $objWMIService.ExecQuery("Select * from Win32_GroupUser")
If IsObj($colSettings) Then
For $objComputer In $colSettings
If $objComputer.AccountType <> '' Then
Return MsgBox(0, "RETURN", "AccountType: " & $objComputer.AccountType & #CRLF & "Full Name: " & $objComputer.FullName & #CRLF & "Caption: " & $objComputer.Caption & #CRLF & "Name: " & $objComputer.Name)
EndIf
Next
Else
MsgBox(0, "RETURN", $colSettings & " IS NOT AN OBJ")
EndIf
Else
MsgBox(0, "RETURN", $objWMIService & " IS NOT AN OBJ")
EndIf
EndFunc ;==>User
However, no output is being returned. Is my query correct at all?
Try this : "Computer Info UDF"
Also, I found this old snippet. (Not tested!)
Dim $InGroup
$oMyError = ObjEvent("AutoIt.Error", "ComError")
If UserInGroup(#LogonDomain, #UserName, "Administrator") Then
MsgBox(0, "Validate", #LogonDomain & "/" & #UserName & " : User in your groupname " & $InGroup)
Else
MsgBox(0, "Validate", #LogonDomain & "/" & #UserName & " : User NOT in your groupname")
EndIf
Exit
; Check if User is in a group
Func UserInGroup($Domain, $UserName, $InGroup)
;local $sRet
Local $objUser = ObjGet("WinNT://" & $Domain & "/" & $UserName)
For $oGroup In $objUser.Groups
If $oGroup.Name = $InGroup Then Return 1
Next
Return 0
EndFunc ;==>UserInGroup
;COM Error function
Func ComError()
If IsObj($oMyError) Then
$HexNumber = Hex($oMyError.number, 8)
SetError($HexNumber)
Else
SetError(1)
EndIf
Return 0
EndFunc ;==>ComError
#cs
; Generated by AutoIt Scriptomatic
$wbemFlagReturnImmediately = 0x10
$wbemFlagForwardOnly = 0x20
$colItems = ""
$strComputer = "localhost"
$Output=""
$Output = $Output & "Computer: " & $strComputer & #CRLF
$Output = $Output & "==========================================" & #CRLF
$objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\CIMV2")
$colItems = $objWMIService.ExecQuery("SELECT * FROM Win32_GroupUser", "WQL", _
$wbemFlagReturnImmediately + $wbemFlagForwardOnly)
If IsObj($colItems) then
For $objItem In $colItems
$Output = $Output & "GroupComponent: " & $objItem.GroupComponent & #CRLF
$Output = $Output & "PartComponent: " & $objItem.PartComponent & #CRLF
if Msgbox(1,"WMI Output",$Output) = 2 then ExitLoop
$Output=""
Next
Else
Msgbox(0,"WMI Output","No WMI Objects Found for class: " & "Win32_GroupUser" )
Endif
#ce
#include <Constants.au3> ; required for StdoutRead
; populate $groupstring with the output of net user /domain
; remove the /domain if you are just interested in local machine groups
$foo = Run(#ComSpec & " /c net user " & #UserName & " /domain", #SystemDir, #SW_HIDE, $STDOUT_CHILD)
$groupstring = ""
While 1
$groupstring &= StdoutRead($foo)
If #error = -1 Then ExitLoop
WEnd
Func ingroup($which)
If $which = "*" Then Return 1
$which = StringLeft($which, 21) ; net user /domain returns only the first 21 chars of each group
$which = "*" & $which
If StringInStr($groupstring, $which) Then
Return 1
Else
Return 0
EndIf
EndFunc ;==>ingroup
;example usage
If ingroup("Domain Admins") Then
$admin = True
Else
$admin = False
EndIf

Regex Classic ASP

I've currently got a string which contains a URL, and I need to get the base URL.
The string I have is http://www.test.com/test-page/category.html
I am looking for a RegEx that will effectively remove any page/folder names at the end. The issue is that some people may enter the domain in the following formats:
http://www.test.com
www.test.co.uk/
www.test.info/test-page.html
www.test.gov/test-folder/test-page.html
It must return http://www.websitename.ext/ each time i.e. the domain name and extension (e.g. .info .com .co.uk etc) with a forward slash at the end.
Effectively it needs to return the base URL, without any page/folder names. Is there any easy way to do with with a Regular Expression?
Thanks.
My approach: Use a RegEx to extract the domain name. Then add http: to the front and / to the end. Here's the RegEx:
^(?:http:\/\/)?([\w_]+(?:\.[\w_]+)+)(?=(?:\/|$))
Also see this answer to the question Extract root domain name from string. (It left me somewhat disatisfied, although pointed out the need to account for https, the port number, and user authentication info which my RegEx does not do.)
Here is an implementation in VBScript. I put the RegEx in a constant and defined a function named GetDomainName(). You should be able to incorporate that function in your ASP page like this:
normalizedUrl = "http://" & GetDomainName(url) & "/"
You can also test my script from the command prompt by saving the code to a file named test.vbs and then passing it to cscript:
cscript test.vbs
Test Program
Option Explicit
Const REGEXPR = "^(?:http:\/\/)?([\w_]+(?:\.[\w_]+)+)(?=(?:\/|$))"
' ^^^^^^^^^ ^^^^^^ ^^^^^^^^^^ ^^^^
' A B1 B2 C
'
' A - An optional 'http://' scheme
' B1 - Followed by one or more alpha-numeric characters
' B2 - Followed optionally by one or more occurences of a string
' that begins with a period that is followed by
' one or more alphanumeric characters, and
' C - Terminated by a slash or nothing.
Function GetDomainName(sUrl)
Dim oRegex, oMatch, oMatches, oSubMatch
Set oRegex = New RegExp
oRegex.Pattern = REGEXPR
oRegex.IgnoreCase = True
oRegex.Global = False
Set oMatches = oRegex.Execute(sUrl)
If oMatches.Count > 0 Then
GetDomainName = oMatches(0).SubMatches(0)
Else
GetDomainName = ""
End If
End Function
Dim Data : Data = _
Array( _
"xhttp://www.test.com" _
, "http://www..test.com" _
, "http://www.test.com." _
, "http://www.test.com" _
, "www.test.co.uk/" _
, "www.test.co.uk/?q=42" _
, "www.test.info/test-page.html" _
, "www.test.gov/test-folder/test-page.html" _
, ".www.test.co.uk/" _
)
Dim sUrl, sDomainName
For Each sUrl In Data
sDomainName = GetDomainName(sUrl)
If sDomainName = "" Then
WScript.Echo "[ ] [" & sUrl & "]"
Else
WScript.Echo "[*] [" & sUrl & "] => [" & sDomainName & "]"
End If
Next
Expected Output:
[ ] [xhttp://www.test.com]
[ ] [http://www..test.com]
[ ] [http://www.test.com.]
[*] [http://www.test.com] => [www.test.com]
[*] [www.test.co.uk/] => [www.test.co.uk]
[*] [www.test.co.uk/?q=42] => [www.test.co.uk]
[*] [www.test.info/test-page.html] => [www.test.info]
[*] [www.test.gov/test-folder/test-page.html] => [www.test.gov]
[ ] [.www.test.co.uk/]
I haven't coded Classic ASP in 12 years and this is totally untested.
result = "http://" & Split(Replace(url, "http://",""),"/")(0) & "/"