2

我当前的项目围绕着将文档中的多个测试用例转换为与测试用例管理系统兼容的 XML 格式。在许多情况下,标题以许多票证标识符、文档位置编号等为前缀,在将它们上传到系统之前需要将其删除。

鉴于这些票证标识符中的许多可能存在于标题中的其他位置并且完全有效,因此我以当前形式编写了翻译,以便仅检查字符串的开头是否有正则表达式。我写了两种方法,结果各不相同。

样本输入

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;)。

矛盾的是:很抱歉这个问题很长,如果我错过了什么,请告诉我。

编辑:忘了说,除破折号外的所有正则表达式都已在其他地方进行了测试,并且已知适用于所有输入内容

编辑二:按照@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 演示中看到,上面的表达式确实与您的两个示例匹配。


可能有一个你可能感兴趣的优雅的简化。

\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

一个统治它们的正则表达式看起来像

^ # 字符串开头
([0-9]\.[0-9.]+).*? # 数字和点
\((C[0-2])\).*? # C0、C1、C2
((TID#\S+).*?)? # 时间...
((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 回答