I'm trying to write a regular expression to return the method contents between method name and the following method name. I'll further parse that for info I'm extracting. How do I do that? So far I have it working to get the info from the method name on, but don't know how to get it to stop at the following method name. Any other ideas would be appreciated.
This returns the lines that match string method name (but I want entire method):
$contents = Get-Content $codePath | Select-String -Pattern "$methodNameToReturn.*" -AllMatches
This is where I'm trying to get it to end the string returned at the following method, but it's not finding anything:
Get-MethodContents -codePath $File[0] -methodNameToReturn "GetStatusFromCode" -followingMethodName "SkipPage"
Function Get-MethodContents{
[cmdletbinding()]
Param ( [string]$codePath, [string]$methodNameToReturn, [string]$followingMethodName)
Process
{
$contents = ""
Write-Host "In GetMethodContents method File:$codePath method:$methodNameToReturn followingMethod:$followingMethodName" -ForegroundColor Green
#Switch -regex (Get-Content -Path $codePath)
#{
#'^(.*)/s'{$contents=$switch.current}
#}
$contents = Get-Content $codePath | Select-String -Pattern "($methodNameToReturn.*$followingMethodName)" -AllMatches
Write-Host "File Contents Found: $contents" -ForegroundColor Cyan
}#End of Process
}#End of Function
Here's example code trying to match (what's important is I get what's inside GetStatusFromCode method to parse further):
...
bool ClassName::GetStatusFromCode( DWORD errorCode,
TCHAR *errorStr,
DWORD &outError,
COM_ERROR_SEVERITY &outSeverity,
TCHAR *outDevStr)
{
m_bRestart = TRUE;
BYTE MinorCode = 0;
// Get and check width
DWORD dwLength = 0;
BYTE buff[ 2 ] = {0};
//
if ( chcusb_getInfo( (WORD)kPINFTAG_SVCINFO, buff, &dwLength ) == FALSE )
{
// Error
}
MinorCode = buff[1];
switch( errorCode )
{
//case kRESULT_NOERROR:
case kRESULT_MEMFULLERR:
//code
_sprintf(outDevStr, _T("8000 - (Comm Err)"), errStr);
outError = errVar;
break;
case kRESULT_USBNOTFOUND:
//code
_sprintf(outDevStr, _T("8001 - (Comm 1 Err)"), errStr);
outError = errVar;
break;
default:
// Maybe communication error
break;
}
m_dwErrorCode = outError;
if ( m_bRestart == TRUE )
{
return true;
}
else
{
return false;
}
}
////////////////////////////////////////
//
// METHOD NAME: SkipPage
//
////////////////////////////////////////
bool ClassName::SkipPage( GUID JobID, DWORD dwPageNum )
...
This is where I've looked for more info:
match characters across multiple lines
My question is how do I extract contents of that method name entirely? I don't care if it includes the followingMethodName, but it needs to get multiple lines until the end text of the method of interest, methodNameToReturn. Yes, I know this is weird to want to do, but it's what is being asked for. This is PowerShell 5.1.
Edit: I exited the powershell file and it looks like it's finding the files still, but now it's not finding anything with either regex.
CodePudding user response:
First, to match multiple lines, you must get the "raw" content of the file. Get-Content
returns a list of strings by default, but -Raw
gives you a single string that you can match through:
$contents = Get-Content $codePath -Raw
Then to regex across multiple lines, you must capture line-ending characters. .*
excludes line endings, so I use either [\s\S]*
for this on windows files instead. I'm also adding Classname::
from your example because it seems like a good place to start/end:
# -match usually returns true/false, so suppress
$null = $contents -match "(Classname::$methodNameToReturn[\s\S]*)Classname::$followingMethodName"
# Return the contents of the first capture group () as a single string
$Matches.Item(1)
More info about -Match
CodePudding user response:
Shy of writing a fullblown C parser, one useful heuristic would be to consume the method body until you reach a closing }
that corresponds to the opening {
- the nice thing about this approach is that PowerShell's regex operators can find them for you!
The .NET regex engine supports something called balancing groups, which allows us to keep track of how many opening brackets we've encountered, and decrement the counter every time we encounter a corresponding closing bracket:
Select-String -Path $codePath -Pattern "(?s)$methodNameToReturn\s*\(.*\)\s*\{(?:[^{}]|(?<bracket>\{)|(?<-bracket>\})) (?(bracket)(?!))\}"