1

それぞれの括弧 (param \d+) の間の内容を確実に取得できる正規表現 (Coldfusion または Java) を探しています。数十種類の正規表現を試しましたが、最も近いものは次のとおりです。

\(param \d+\) = \[(type='[^']*', class='[^']*', value='(?:[^']|'')*', sqltype='[^']*')\]

CF から返された文字列が値パラメーターから一重引用符をエスケープした場合、これは完璧です。しかし、そうではないので、惨めに失敗します。次のような否定的な先読みのルートに進みます。

\[(type='[^']*', class='[^']*', value='(?:(?!', sqltype).)*', sqltype='[^']*')\]

なんらかの不自然な理由で、文字通り, sqltype値に含まれるコードが存在しない限り、それは素晴らしいことです。見つかったすべての開き括弧と閉じ括弧の内容をすくい取るように正規表現に単純に指示できないとは信じがたいですが、繰り返しになりますが、その限界を知るのに十分な正規表現を知りません。

解析しようとしている文字列の例を次に示します。

(param 1) = [type='IN', class='java.lang.Integer', value='47', sqltype='cf_sql_integer'] , (param 2) = [type='IN', class='java.lang.String', value='asf , O'Reilly, really?', sqltype='cf_sql_varchar'] , (param 3) = [type='IN', class='java.lang.String', value='Th[is]is Ev'ery'thing That , []can break it ', sqltype= ', sqltype='cf_sql_varchar']

好奇心旺盛な人のために、これはCopyable Coldfusion SQL Exceptionのサブ質問です。

編集

これは、CF9.1 で @Mena の回答を実装しようとする私の試みです。悲しいことに、文字列の処理が完了していません。\\最初に実行するためだけにを置き換える必要がありまし\たが、実装にまだ問題がある可能性があります。

これは与えられた文字列です (パイプは単に境界を示すためのものです):

| (param 1) = [type='IN', class='java.lang.Integer', value='47', sqltype='cf_sql_integer'] , (param 2) = [type='IN', class='java.lang.String', value='asf , O'Reilly], really?', sqltype='cf_sql_varchar'] , (param 3) = [type='IN', class='java.lang.String', value='Th[is]is Ev'ery'thing That , []can break it ', sqltype ', sqltype='cf_sql_varchar'] | 

これは私の実装です:

    <cfset var outerPat = createObject("java","java.util.regex.Pattern").compile(javaCast("string", "\((.+?)\)\s?\=\s?\[(.+?)\](\s?,|$)"))>
    <cfset var innerPat = createObject("java","java.util.regex.Pattern").compile(javaCast("string", "(.+?)\s?\=\s?'(.+?)'\s?,\s?"))>
    <cfset var outerMatcher = outerPat.matcher(javaCast("string", arguments.params))>

    <cfdump var="Start"><br />
    <cfloop condition="outerMatcher.find()">     
        <cfdump var="#outerMatcher.group(1)#"> (<cfdump var="#outerMatcher.group(2)#">)<br />
        <cfset var innerMatcher = innerPat.matcher(javaCast("string", outerMatcher.group(2)))>
        <cfloop condition="innerMatcher.find()">
            <cfoutput>|__</cfoutput><cfdump var="#innerMatcher.group(1)#"> --> <cfdump var="#innerMatcher.group(2)#"><br />
        </cfloop>
        <br />
    </cfloop>
    <cfabort>

そして、これが印刷されたものです:

Start 
param 1 ( type='IN', class='java.lang.Integer', value='47', sqltype='cf_sql_integer' )
|__ type --> IN 
|__ class --> java.lang.Integer 
|__ value --> 47 

param 2 ( type='IN', class='java.lang.String', value='asf , O'Reilly )
|__ type --> IN 
|__ class --> java.lang.String 

End
4

2 に答える 2

2

サンプル入力で機能する Java 正規表現パターンを次に示します。

(?x)

# lookbehind to check for start of string or previous param
# java lookbehinds must have max length, so limits sqltype
(?<=^|sqltype='cf_sql_[a-z]{1,16}']\ ,\ )

# capture the full string for replacing in the orig sql
# and just the position to verify against the match position
(\(param\ (\d+)\))

\ =\ \[

# type and class wont contain quotes
   type='([^']++)'
,\ class='([^']++)'

# match any non-quote, then lazily keep going
,\ value='([^']++.*?)'

# sqltype is always alphanumeric
,\ sqltype='cf_sql_[a-z]+'

\]

# lookahead to check for end of string or next param
(?=$|\ ,\ \(param\ \d+\)\ =\ \[)

(この(?x)フラグは、エスケープされていない空白と、ハッシュと行末の間を無視するコメント モード用です。)

そして、これが CFML で実装されたそのパターンです (CF9,0,1,274733 でテスト済み)。cfRegex (CFML での Java 正規表現の操作を容易にするライブラリ) を使用してそのパターンの結果を取得し、いくつかのチェックを行って、予想される数のパラメーターが見つかったことを確認します。

<cfsavecontent variable="Input">
(param 1) = [type='IN', class='java.lang.Integer', value='47', sqltype='cf_sql_integer']
 , (param 2) = [type='IN', class='java.lang.String', value='asf , O'Reilly, really?', sqltype='cf_sql_varchar']
 , (param 3) = [type='IN', class='java.lang.String', value='Th[is]is Ev'ery'thing That , []can break it ', sqltype= ', sqltype='cf_sql_varchar']
</cfsavecontent>
<cfset Input = trim(Input).replaceall('\n','')>

<cfset cfcatch = 
    { params = input
    , sql = 'SELECT stuff FROM wherever WHERE (param 3) is last param'
    }/>

<cfsavecontent variable="ParamRx">(?x)

    # lookbehind to check for start or previous param
    # java lookbehinds must have max length, so limits sqltype
    (?<=^|sqltype='cf_sql_[a-z]{1,16}']\ ,\ )

    # capture the full string for replacing in the orig sql
    # and just the position to verify against the match position
    (\(param\ (\d+)\))

    \ =\ \[

    # type and class wont contain quotes
       type='([^']++)'
    ,\ class='([^']++)'

    # match any non-quote, then lazily keep going if needed
    ,\ value='([^']++.*?)'

    # sqltype is always alphanumeric
    ,\ sqltype='cf_sql_[a-z]+'

    \]

    # lookahead to check for end or next param
    (?=$|\ ,\ \(param\ \d+\)\ =\ \[)

</cfsavecontent>

<cfset FoundParams = new Regex(ParamRx).match
    ( text = cfcatch.params
    , returntype = 'full'
    )/>

<cfset LastParamPos = cfcatch.sql.lastIndexOf('(param ') + 7 />
<cfset LastParam = ListFirst( Mid(cfcatch.sql,LastParamPos,3) , ')' ) />

<cfif LastParam NEQ ArrayLen(FoundParams) >
    <cfset ProblemsDetected = true />
<cfelse>
    <cfset ProblemsDetected = false />

    <cfloop index="i" from=1 to=#ArrayLen(FoundParams)# >

        <cfif i NEQ FoundParams[i].Groups[2] >
            <cfset ProblemsDetected = true />
        </cfif>

    </cfloop>
</cfif>

<cfif ProblemsDetected>
    <big>Something went wrong!</big>
<cfelse>
    <big>All seems fine</big>
</cfif>

<cfdump var=#FoundParams# />

これは、別のパラメーターの値内にパラメーター全体を埋め込む場合に実際に機能します。2 つ (またはそれ以上) 試行すると失敗しますが、少なくともチェックでこの失敗が検出されるはずです。

ダンプ出力は次のようになります。

ダンプ出力

うまくいけば、ここにあるすべてが理にかなっています。質問があればお知らせください。

于 2013-08-09T19:45:56.873 に答える
0

おそらく専用のパーサーを使用しますが、2 つPatternの s とネストされたループを使用してそれを行う方法の例を次に示します。

// the input String
String input = "(param 1) = " +
        "[type='IN', class='java.lang.Integer', value='47', sqltype='cf_sql_integer'] , " +
        "(param 2) = " +
        "[type='IN', class='java.lang.String', value='asf , O'Reilly, really?', " +
        "sqltype='cf_sql_varchar'] , " +
        "(param 3) = " +
        "[type='IN', class='java.lang.String', value='Th[is]is Ev'ery'thing That , "                "[]can break it ', sqltype= ', sqltype='cf_sql_varchar']";

// the Pattern defining the round-bracket expression and the following 
// square-bracket list. Both values within the brackets are grouped for back-reference
// note that what prevents the 3rd case from breaking is that the closing square bracket 
// is expected to be either followed by optional space + comma, or end of input
Pattern outer = Pattern.compile("\\((.+?)\\)\\s?\\=\\s?\\[(.+?)\\](\\s?,|$)");

// the Pattern defining the key-value pairs within the square-bracket groups
// note that both key and value are grouped for back-reference
Pattern inner = Pattern.compile("(.+?)\\s?\\=\\s?'(.+?)'\\s?,\\s?");
Matcher outerMatcher = outer.matcher(input);
// iterating over the outer Pattern (type x) = [myKey = myValue, ad lib.], or end of input
while (outerMatcher.find()) {
    System.out.println(outerMatcher.group(1));
    Matcher innerMatcher = inner.matcher(outerMatcher.group(2));
    // iterating over the inner Pattern myKey = myValue
    while (innerMatcher.find()) {
        System.out.println("\t" + innerMatcher.group(1) + " --> " + innerMatcher.group(2));
    }
}

出力:

param 1
    type --> IN
    class --> java.lang.Integer
    value --> 47
param 2
    type --> IN
    class --> java.lang.String
    value --> asf , O'Reilly, really?
param 3
    type --> IN
    class --> java.lang.String
    value --> Th[is]is Ev'ery'thing That , []can break it 
于 2013-08-09T17:53:47.663 に答える