首页 > 解决方案 > 如何删除括号中的最后一个文本(优雅而简单)

问题描述

所以我有一些工作代码。

我想从字符串中删除最后一个带括号的(?)文本......只要它的“最后一个”(即后面没有空格或句号)。

所以

let x1 = remove "hello how are you.   "
let x2 = remove "hello how are you. (remove me)   "
let x3 = remove "hello how are you(don't remove me!).,   "

val x1 : string = "hello how are you.   "
val x2 : string = "hello how are you.    "
val x3 : string = "hello how are you(don't remove me!).,   "

我需要使用不支持正则表达式并且(有点)功能性并且非常基本的语言来执行此操作。(它的 XSLT 1.0)

我不太喜欢在 XSLT 中进行黑客攻击,所以我在 f# 中编写了一个简单的例程。

let remove s = 
    match (s : string).LastIndexOf '(' with
    | -1 ->
        s
    | lastOpen ->
        let rest = s.Substring lastOpen
        match rest.LastIndexOf ')' with
        | -1 -> 
            s
        | lastClose -> 
            let after = rest.Substring (lastClose + 1)
            if after.Replace(".","") |> String.IsNullOrWhiteSpace then
                s.Substring (0,lastOpen) + after
            else
                s

我不能使用正则表达式,(或编写某种解析器),它只是一个尽可能简单的基本算法。

以上广泛适用(我可以看到它没有的边缘情况......但不要太挂断)。

有什么更简单的(但不那么丑陋)?

编辑#1 帖子接受回复。

作为一个发人深省的想法,这是一个 4 行 f# 程序的 xslt 版本!

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:variable name="foo">
      <xsl:call-template name="removeParenthesisIf">
        <xsl:with-param name="s" select="'foo bar dfsfsfffs)'"/>
        <xsl:with-param name="maxCount" select="20"/>
      </xsl:call-template>
    </xsl:variable>
  </xsl:template>
  <xsl:template name="removeParenthesisIf">
    <xsl:param name="s"/>
    <xsl:param name="maxCount"/>
    <xsl:choose>
      <xsl:when test="substring($s,string-length($s)) = ')'">
        <xsl:variable name="lastOpen">
          <xsl:call-template name="lastCharIndex">
            <xsl:with-param name="pText" select="$s"/>
            <xsl:with-param name="pChar" select="'('"/>
          </xsl:call-template>          
        </xsl:variable>
        <xsl:choose>
          <xsl:when test="($maxCount &gt; string-length($s) - $lastOpen + 1) and not(string-length($s) = $lastOpen )">
            <xsl:value-of select="substring($s,1,$lastOpen - 1)"/>
          </xsl:when>
          <xsl:otherwise>
            <xsl:value-of select="$s"/>
          </xsl:otherwise>
        </xsl:choose>
      </xsl:when>
      <xsl:otherwise>
        <xsl:value-of select="$s"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
  <xsl:template name="lastCharIndex">
    <xsl:param name="pText"/>
    <xsl:param name="pChar" select="' '"/>
    <xsl:variable name="vRev">
      <xsl:call-template name="reverse">
        <xsl:with-param name="pStr" select="$pText"/>
      </xsl:call-template>
    </xsl:variable>
    <xsl:value-of select="string-length($pText) - string-length(substring-before($vRev, $pChar))"/>
  </xsl:template>
  <xsl:template name="reverse">
    <xsl:param name="pStr"/>
    <xsl:variable name="vLength" select="string-length($pStr)"/>
    <xsl:choose>
      <xsl:when test="$vLength = 1">
        <xsl:value-of select="$pStr"/>
      </xsl:when>
      <xsl:otherwise>
        <xsl:variable name="vHalfLength" select="floor($vLength div 2)"/>
        <xsl:variable name="vrevHalf1">
          <xsl:call-template name="reverse">
            <xsl:with-param name="pStr"
                 select="substring($pStr, 1, $vHalfLength)"/>
          </xsl:call-template>
        </xsl:variable>
        <xsl:variable name="vrevHalf2">
          <xsl:call-template name="reverse">
            <xsl:with-param name="pStr"
                 select="substring($pStr, $vHalfLength+1)"/>
          </xsl:call-template>
        </xsl:variable>
        <xsl:value-of select="concat($vrevHalf2, $vrevHalf1)"/>
      </xsl:otherwise>
    </xsl:choose>
  </xsl:template>
</xsl:stylesheet>

标签: f#

解决方案


我能想到的最简单的方法,主要使用内置的字符串函数,如下所示:

let remove (s:string) = 
  if s.TrimEnd(' ').EndsWith(")") then
    let last = s.LastIndexOf('(')
    s.Remove(last, s.LastIndexOf(')') - last + 1)
  else s

有两个技巧:

  • 首先,)如果我们从末尾删除所有空格,我们检查字符串是否以结尾。这是检测你有东西要删除的情况。
  • 如果是这种情况,您可以使用Remove. 这假设字符串格式正确并且确实有一个左括号 - 所以这是您可能需要添加的额外检查。

推荐阅读