f# - 如何删除括号中的最后一个文本(优雅而简单)
问题描述
所以我有一些工作代码。
我想从字符串中删除最后一个带括号的(?)文本......只要它的“最后一个”(即后面没有空格或句号)。
所以
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 > 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>
解决方案
我能想到的最简单的方法,主要使用内置的字符串函数,如下所示:
let remove (s:string) =
if s.TrimEnd(' ').EndsWith(")") then
let last = s.LastIndexOf('(')
s.Remove(last, s.LastIndexOf(')') - last + 1)
else s
有两个技巧:
- 首先,
)
如果我们从末尾删除所有空格,我们检查字符串是否以结尾。这是检测你有东西要删除的情况。 - 如果是这种情况,您可以使用
Remove
. 这假设字符串格式正确并且确实有一个左括号 - 所以这是您可能需要添加的额外检查。