2

私の現在のプロジェクトは、ドキュメント内の多数のテスト ケースを、テスト ケース管理システムと互換性のある XML 形式に変換することを中心に展開しています。これらのケースの多くでは、タイトルの前に多数のチケット ID、ドキュメントの場所番号などが付けられます。これらは、システムにアップロードする前に削除する必要があります。

これらのチケット ID の多くがタイトルの他の場所に存在し、完全に有効である可能性があることを考慮して、現在の形式で翻訳を作成し、文字列の先頭のみが正規表現でチェックされるようにしました。私は 2 つのアプローチを書きましたが、結果はさまざまです。

サンプル入力

1.

<case-name>3.1.6 (C0) TID#EIIY CHM-2213 BZ-7043 Client side Java Upgrade R8</case-name>

2.

<case-name>4.2.7    (C1) TID#F1DR – AIP - EHD-319087 - BZ6862 - Datalink builder res...</case-name>

望ましい出力

1.

<tr:summary>Client side Java Upgrade R8</tr:summary>

2.

<tr:summary>Datalink builder res...</tr:summary>

最初のアプローチ

    <xsl:template match="case-name">
    <tr:summary>
        <xsl:variable name="start">
            <xsl:apply-templates/>
        </xsl:variable>
        <xsl:variable name="start" select="normalize-space($start)"/>
        <xsl:variable name="noFloat"        select="normalize-space(fn:remFirstRegEx($start,        '^[0-9]+([.][0-9]+)*'                       ))"/>
        <xsl:variable name="noFloatDash"    select="normalize-space(fn:remFirstRegEx($noFloat,      '^[\p{Pd}]'                                 ))"/>
        <xsl:variable name="noC"            select="normalize-space(fn:remFirstRegEx($noFloatDash,  '^\(C[0-2]\)'                               ))"/>
        <xsl:variable name="noCDash"        select="normalize-space(fn:remFirstRegEx($noC,          '^[\p{Pd}]'                                 ))"/>
        <xsl:variable name="noTID"          select="normalize-space(fn:remFirstRegEx($noCDash,      '^(TID)(#|\p{Pd})(\w+)'                     ))"/>
        <xsl:variable name="noTIDDash"      select="normalize-space(fn:remFirstRegEx($noTID,        '^[\p{Pd}]'                                 ))"/> 
        <xsl:variable name="noAIP"          select="normalize-space(fn:remFirstRegEx($noTIDDash,    '^AIP'                                      ))"/>
        <xsl:variable name="noAIPDash"      select="normalize-space(fn:remFirstRegEx($noAIP,        '^[\p{Pd}]'                                 ))"/>
        <xsl:variable name="noCHM"          select="normalize-space(fn:remFirstRegEx($noAIPDash,    '^(CHM)[\p{Pd}]([0-9]+)'                    ))"/>
        <xsl:variable name="noCHMDash"      select="normalize-space(fn:remFirstRegEx($noCHM,        '^[\p{Pd}]'                                 ))"/>
        <xsl:variable name="noEHD"          select="normalize-space(fn:remFirstRegEx($noCHMDash,    '^(EHD)[\p{Pd}]([0-9]+)'                    ))"/>
        <xsl:variable name="noEHDDash"      select="normalize-space(fn:remFirstRegEx($noEHD,        '^[\p{Pd}]'                                 ))"/>   
        <xsl:variable name="noBZ"           select="normalize-space(fn:remFirstRegEx($noEHDDash,    '^(BZ)(((#|\p{Pd})[0-9]+)|[0-9]+)'          ))"/>
        <xsl:variable name="noBZDash"       select="normalize-space(fn:remFirstRegEx($noBZ,         '^[\p{Pd}]'                                 ))"/>
        <xsl:variable name="noTT"           select="normalize-space(fn:remFirstRegEx($noBZDash,     '^(TT)[#](\w)+'                             ))"/>
        <xsl:variable name="noTTDash"       select="normalize-space(fn:remFirstRegEx($noTT,         '^[\p{Pd}]'                                 ))"/>
        <xsl:variable name="nobrack"        select="normalize-space(fn:remFirstRegEx($noTTDash,     '^\[(.*?)\]'                                ))"/>
        <xsl:variable name="noBrackDash"    select="normalize-space(fn:remFirstRegEx($nobrack,      '^[\p{Pd}]'                                 ))"/>
        <xsl:value-of select="normalize-space($noBrackDash)"/>
    </tr:summary>
</xsl:template>

<xsl:function name="fn:remFirstRegEx">
    <xsl:param name="inString"/>
    <xsl:param name="regex"/>

    <xsl:variable name="words" select="tokenize($inString, '\p{Z}')"/>
    <xsl:variable name="outString">
        <xsl:for-each select="$words">
            <xsl:if test="not(matches(., $regex)) or index-of($words, .) > 1">
                <xsl:value-of select="."/><xsl:text> </xsl:text>
            </xsl:if>
        </xsl:for-each>
    </xsl:variable>

    <xsl:value-of select="string-join($outString, '')">
</xsl:function>

注:この翻訳では、名前空間 fn は単なる「関数/名前空間」であり、独自の関数を記述するために使用されます。

最初の結果

1.成功

<tr:summary>Client side Java Upgrade R8</tr:summary>

2.失敗

<tr:summary>- EHD-319087 - BZ6862 - Datalink builder resolution selector may drop leading zeros on coordinate seconds</tr:summary>

第二のアプローチ

<xsl:function name="fn:remFirstRegEx">
    <xsl:param name="inString"/>
    <xsl:param name="regex"/>

    <xsl:analyze-string select="$inString" regex="$regex">
        <xsl:non-matching-substring>
            <xsl:value-of select="."/>
        </xsl:non-matching-substring>
    </xsl:analyze-string>
</xsl:function>

このアプローチは完全に失敗します。より明白な解決策であり、まったく機能しなかったため、ここに含めます。

上記のソリューションには多数の正規表現があることに注意してください。これは、通過する可能性のあるすべての ID を説明するためです。幸いなことに、ID は一貫した順序になっているようです。

私が結論付けたように、問題はダッシュにあります。私は、翻訳が失敗したドキュメントのすべての場合において、失敗した ID の前後にダッシュが付けられていることを指摘しました。先行するだけなら問題なく通ります。それに従うだけなら問題ありません。どちらも落下する場所であり、興味深いことに、ダッシュはストリングからすでに除去されているように見えますが、まだ表示されています。

ここでは、通常のダッシュ ( &#8211;) とマイナス記号 ( &#45;) の 2 種類のダッシュが使用されます。

逆説的に: 長い質問で申し訳ありません。

編集: 言い忘れましたが、ダッシュを除くすべての正規表現は他の場所でテストされており、すべての入力内容で動作することが知られています。

EDIT II: @ acheong87 のソリューションに従って、次を実行しようとしました。

<xsl:template match="case-name">
        <tr:summary>
        <xsl:variable name="regEx" select=
        "'^[\s\p{Pd}]*(\d+([.]\d+)*)?[\s\p{Pd}]*(\(C[0-2]\))?([\s\p{Pd}]*(TID|AIP|CHM|EHD|BZ|TT)((#|\p{Pd}|)\w+|))*[\s\p{Pd}]*(\[.*?\])?'"/>
        <xsl:analyze-string select="string(.)" regex="{$regEx}">
            <xsl:non-matching-substring>
                <xsl:value-of select="."/>
            </xsl:non-matching-substring>
        </xsl:analyze-string>
    </tr:summary>
</xsl:template>

そしてサクソンは私に次のエラーを与えます:

Error at xsl:analyze-string at line (for our purposes, 5):
XTDE1150: The regular expression must not be one that matches a zero-length string

すべてがオプションであることを考えると、なぜそれが発生するのかがわかります。このエラーが発生しない別の実行方法はありますか?

再度、感謝します。

4

2 に答える 2

2

以下は、単一の正規表現に含まれる主なコンポーネントです。表現を一部書き直しました。

\d+([.]\d+)*
\(C[0-2]\)
TID(#|\p{Pd})\w+
AIP
CHM[\p{Pd}]\d+
EHD[\p{Pd}]\d+
BZ(#|\p{Pd}|)\d+
TT#\w+
\[.*?\]

オプションにするために各コンポーネントをラップする(...)?必要があり、すべてのコンポーネントは区切り記号 で結合する必要があります[\s\p{Pd}]*。これにより、次が生成されます。

^[\s\p{Pd}]*(\d+([.]\d+)*)?[\s\p{Pd}]*(\(C[0-2]\))?[\s\p{Pd}]*(TID(#|\p{Pd})\w+)?[\s\p{Pd}]*(AIP)?[\s\p{Pd}]*(CHM[\p{Pd}]\d+)?[\s\p{Pd}]*(EHD[\p{Pd}]\d+)?[\s\p{Pd}]*(BZ(#|\p{Pd}|)\d+)?[\s\p{Pd}]*(TT#\w+)?[\s\p{Pd}]*(\[.*?\])?

この Rubular デモでは、上記の式が実際に 2 つの例と一致することがわかります。


あなたが興味を持っているかもしれないエレガントな単純化があるかもしれません.

\d+([.]\d+)*
\(C[0-2]\)
(TID|AIP|CHM|EHD|BZ|TT)((#|\p{Pd}|)\w+|)
\[.*?\]

のようないくつかのコードAIPは分離する必要があるかもしれませんが、このバージョンの精神を見ることができます。つまり、有効なタイトルがそのようなコードで始まる可能性は低いです。実際、あなたの例では、などの可能な組み合わせが欠落EHD#している可能性が高く、将来的には現れる可能性がありますが、過去に基づいた定式化は欠落する可能性があります. (もちろん、未来ない場合、私の主張は意味がありません。処理する必要があるのは、所有しているデータだけです。) ただし、未来がある場合は、IMO、この場合は厳密性を緩めたほうがよいでしょう。潜在的な関連する組み合わせをキャプチャする式。

上記は次のようになります。

^[\s\p{Pd}]*(\d+([.]\d+)*)?[\s\p{Pd}]*(\(C[0-2]\))?([\s\p{Pd}]*(TID|AIP|CHM|EHD|BZ|TT)((#|\p{Pd}|)\w+|))*[\s\p{Pd}]*(\[.*?\])?

これがRubular のデモです。

于 2013-07-11T15:05:03.740 に答える
0

それらすべてを支配する1つの正規表現は次のようになります

^ # 文字列の開始
([0-9]\.[0-9.]+).*? # 数字とドット
\((C[0-2])\).*? # C0、C1、C2
((TID#\S+).*?)? # TID...
((AIP).*?)? # AIP...
((CHM\S+).*?)? #CHM...
((EHD\S+).*?)? # EHD...
((BZ\S+).*?)? #BZ...
(\w.*)? # フリーテキスト
$ # 文字列の終わり
^([0-9]\.[0-9.]+).*?\((C[0-2])\).*?((TID#\S+).*?)?((AIP )*?)?((CHM\S+).*?)?((EHD\S+).*?)?((BZ\S+).*?)?(\w.*)?$

http://rubular.com/r/pPxKBVwJaE

次の.*?マッチが始まるまで任意の区切り文字を食べます。ほとんどの一致はオプションであり、オプションである必要がある以上の場合もあります。(...)?必須にしたい一致の囲みを削除します。オプションのグループはカウントされますが、空にすることができます。

すべてを一緒に入れて

<xsl:variable name="linePattern">           <!--  group|contents        -->
  <xsl:text>^</xsl:text>                    <!--        start of string -->
  <xsl:text>([0-9]\.[0-9.]+).*?</xsl:text>  <!--      1 digits and dots -->
  <xsl:text>\((C[0-2])\).*?</xsl:text>      <!--      2 C0, C1, C2      -->
  <xsl:text>((TID#\S+).*?)?</xsl:text>      <!--  3,  4 TID...          -->
  <xsl:text>((AIP).*?)?</xsl:text>          <!--  5,  6 AIP...          -->
  <xsl:text>((CHM\S+).*?)?</xsl:text>       <!--  7,  8 CHM...          -->
  <xsl:text>((EHD\S+).*?)?</xsl:text>       <!--  9, 10 EHD...          -->
  <xsl:text>((BZ\S+).*?)?</xsl:text>        <!-- 11, 12 BZ...           -->
  <xsl:text>(\w.*)?</xsl:text>              <!--     13 free text       -->
  <xsl:text>$</xsl:text>                    <!--        end of string   -->
</xsl:variable>

<xsl:template match="case-name">
  <xsl:analyze-string select="string(.)" regex="{$linePattern}">
    <xsl:matching-substring>
      <tr:summary>
        <part><xsl:value-of select="regex-group(1)" /></part>
        <part><xsl:value-of select="regex-group(2)" /></part>
        <part><xsl:value-of select="regex-group(4)" /></part>
        <part><xsl:value-of select="regex-group(6)" /></part>
        <part><xsl:value-of select="regex-group(8)" /></part>
        <part><xsl:value-of select="regex-group(10)" /></part>
        <part><xsl:value-of select="regex-group(12)" /></part>
        <part><xsl:value-of select="regex-group(13)" /></part>
      </tr:summary>
    </xsl:matching-substring>
    <!--
      possibly include <xsl:non-matching-substring>, <xsl:fallback>
    -->
  </xsl:analyze-string>
</xsl:template>

もちろん、個々のマッチ グループを好きなように扱うことができます。

于 2013-07-11T15:39:10.577 に答える