Question
Brian Schoen · Nov 6, 2020

Piece or String function using Matches [A-Z]

I am trying to match on config items that have the same Vendor name in them for custom alerting.

Example:

FromVendornameSiteADT

ToVendornameORM

Where Vendorname could be several systems that have multiple interfaces.

How can I find all config items (interface names) with the same Vendor name, without explicitly naming them?

I was trying to use $Piece to segment out the CamelCase pieces (as the name I want is always the 2nd Capitalized section), but could not find a way to integrate match regex logic (e.g. [A-Z]) inside $Piece or other String extract functions.

00
4 0 9 127
Log in or sign up to continue

Replies

Hello Brian,

I'm not sure what your other code for this alerting looks like, but would the Ensemble Utility Function "Contains" be useful?

TEST>w ##class(Ens.Util.FunctionSet).Contains("FromVendornameSiteADT","Vendor"))
1

There are also utility functions to convert a string to all upper/lowercase, if you need that also.

Unfortunately, Vendorname is just a placeholder for the section of the String I need to extract.  I'm trying to find a way to pull that section (i.e. the 2nd Capitalized word) from the string without naming it.

i.e.:

FromEpicADT  > "Epic"

ToHealthshareNorthADT  > "Healthshare"

I think this has the same problem I describe in my reply above.  

Hi Brian,

Could you please with below code.

----------------------------------------------------

Class Sample.TempUtil Extends %RegisteredObject
{

ClassMethod GetSecondUpperCase(pInput As %String) As %String
{
 ;w ##class(Sample.TempUtil).GetSecondUpperCase("GetSecondUpperCase")
 SET stsrtpos=$LOCATE(pInput,"[[:upper:]]{1}",2)
 SET endpos=$LOCATE(pInput,"[[:upper:]]{1}",(stsrtpos+1))
 SET result=$EXTRACT(pInput,stsrtpos,(endpos-1))
 
 quit result
}

}
----------------------------------------------------------------

Regards,

Muni Ganesh

Thanks!   I was almost there...  I think this will work nicely!

Have a look at %Regex.Matcher. Since you always want the 2nd capitalized section you can just make that your regex capture group:

    set matcher=##class(%Regex.Matcher).%New("^[A-Z][a-z]*([A-Z][a-z]*)")                             
    set matcher.Text="ToVendornameORM"
    if matcher.Locate() {
        write "Found ",matcher.Group(1)," at position ",matcher.Start,!
    }

This gives me the output:

Found Vendorname at position 1

Thanks!   I think this would have gotten me there too!

Here's the code to get capitalized piece of string by number:

/// Get Capitalized piece.
///   str - string to search
///   piece - 1-based piece to return
/// write ##class(test.CustomQuery).GetCapitalizedPiece()
ClassMethod GetCapitalizedPiece(str As %String = "lowerHelloWorldAgainHelloWorldAgainHelloWorldAgainHelloWorldAgain", piece As %Integer = 1) As %String
{
    
    // Only uppercase letters
    set upper = $tr(str, $zcvt(str, "l"))
    
    // Number of uppercase letteres
    set capCount = $l(upper)
    
    // Quit if requested piece can not exist
    quit:piece>capCount ""
    quit:piece<1 ""
    
    // First letter in our capitalized piece
    set startLetter = $e(upper, piece)
    
    // All previous capitalized letters
    set prevLetters = $e(upper, 1, piece - 1)

    // Check if current capitalized letter is a first capitalized letter
    // If not - skip previous capitalized letters
    if '$find(prevLetters, startLetter) {
        set start = $find(str, startLetter) - 1
    } else {
        set count = $l(prevLetters, startLetter) + 1
        set start = 0
        while $i(count,-1) {
            set start = $find(str, startLetter, start)
        }
        set start = start - 1
    }
    
    // Is this capitalized piece the last one?
    if piece=capCount {
        set end = $l(str)
    } else {
        set end = $find(str, $e(upper, piece + 1), start) - 2
    }

    quit $e(str, start, end)
}

Advantages over regexp:

  • ~50 times faster
  • Get any piece, not only the second one (although generating required regexp by piece number seems easy to do)