删除尾随空格时 Applescript 代码中断

Applescript code breaking when removing trailing spaces

从字符串中删除最后一个字符应该是一段简单的代码,但似乎无缘无故地中断了(无论如何对我来说)。

我正在尝试创建一个简单的脚本来解决同事在文件名和扩展名周围有多余空格时出现的 OneDrive 文件同步问题。

离开很长时间后回到 AppleScript,似乎忘记了一切,只需要了解为什么应该简单的东西似乎让我感到困惑...对我温柔点。

on stripSpaces(thisText)
    local newText
    local pos
    local tempText

    set newText to thisText

    set tempText to ""

    repeat while tempText ≠ newText
        set tempText to newText

        --remove spaces before extension name
        set pos to the offset of ". " in newText

        if pos > 0 then
            set newText to ((characters 1 thru pos of newText) as text) & (characters (pos + 2) thru end of newText) as text
        end if

        --remove spaces before extension
        set pos to the offset of " ." in newText

        if pos > 0 then
            set newText to ((characters 1 thru (pos - 1) of newText) as text) & (characters (pos + 1) thru end of newText) as text
        end if

        --remove leading spaces
        if character 1 of newText = " " then
            set newText to characters 2 thru end of newText as text
        end if

        ---BROKEN SECTION

        --remove trailing spaces
        if (last character of newText) = " " then
            set newText to (characters 1 thru (end of newText) - 1) as text
        end if
    end repeat

    return newText
end stripSpaces

log stripSpaces("   spa     .          nish  . txt  ")

错误 "Can’t get end of \" 水疗中心。完成。文本文件 \”。”从“spa.nish.txt”的最后一个插入点开始的数字 -1728

使用 text 1 thru -1 of newText 获取文本范围要容易得多,其中 -1 是最后一个字符。这也避免了所有 as text 强制转换。

on stripSpaces(thisText)
    local newText
    local pos
    local tempText

    set newText to thisText

    set tempText to ""

    repeat while tempText ≠ newText
        set tempText to newText

        --remove spaces before extension name
        set pos to the offset of ". " in newText

        if pos > 0 then
            set newText to text 1 thru pos of newText & text (pos + 2) thru -1 of newText
        end if

        --remove spaces before extension
        set pos to the offset of " ." in newText

        if pos > 0 then
            set newText to text 1 thru (pos - 1) of newText & text (pos + 1) thru -1 of newText
        end if

        --remove leading spaces
        if first character of newText = space then
            set newText to text 2 thru -1 of newText
        end if

        --remove trailing spaces
        if last character of newText = space then
            set newText to text 1 thru -2 of newText
        end if
    end repeat

    return newText
end stripSpaces

log stripSpaces("   spa     .          nish  . txt  ")

借助 AppleScriptObjC 的一点帮助,整个处理程序可以减少到两行

use AppleScript version "2.4" -- Yosemite (10.10) or later
use framework "Foundation"

on stripSpaces(thisText)
    set nsText to current application's NSString's stringWithString:thisText
    return (nsText's stringByReplacingOccurrencesOfString:" " withString:"") as text
end stripSpaces

log stripSpaces("   spa     .          nish  . txt  ")

您问题的直接答案是您不应在此上下文中使用 'end',而应使用“-1”表示最后一个字符,“-2”表示倒数第二个字符等等。结果最终会是这样的:

on stripSpaces(thisText)
    local newText
    local pos
    local tempText

    set newText to thisText

    set tempText to ""

    repeat while tempText ≠ newText
        set tempText to newText

        --remove spaces before extension name
        set pos to the offset of ". " in newText

        if pos > 0 then
            set newText to ((characters 1 thru pos of newText) as text) & (characters (pos + 2) thru -1 of newText) as text
        end if

        --remove spaces before extension
        set pos to the offset of " ." in newText

        if pos > 0 then
            set newText to ((characters 1 thru (pos - 1) of newText) as text) & (characters (pos + 1) thru -1 of newText) as text
        end if

        --remove leading spaces
        if character 1 of newText = " " then
            set newText to characters 2 thru -1 of newText as text
        end if

        ---BROKEN SECTION

        --remove trailing spaces
        if (last character of newText) = " " then
            set newText to (characters 1 thru -2 of newText) as text
        end if
    end repeat

    return newText
end stripSpaces

log stripSpaces("   spa     .          nish  . txt  ")

但是,如果您的目标只是去掉空格,则可以使用文本项分隔符更有效地做到这一点:

on stripSpaces(thisText)
    set tid to my text item delimiters
    set my text item delimiters to " "  -- break text at spaces
    set textParts to text items of thisText
    set my text item delimiters to ""  -- recombine text without spaces
    set strippedText to textParts as text
    set my text item delimiters to tid
    return strippedText
end stripSpaces

log stripSpaces("   spa     .          nish  . txt  ")

我来晚了一点。 Ted Wrigley 紧盯着球,非常正确地注意到,最简洁、最有效的解决方案是 text item delimiters。在我看来,我认为他提供了迄今为止最合适的答案,这归功于他,这基本上只是一个 follow-up 来说明可以用更紧凑的 two-line 处理程序:

to removeAllWhitespace from input as text
    set text item delimiters to {pi, space, tab, linefeed, return}
    return the input's text items as text
end removeAllWhitespace

我还冒昧地清除了除 space 之外的所有(传统)空白字符,即 tab 字符和 new-line 字符。如果您愿意,您可能可以推断出如何删除这些选项。

调用处理程序:

removeAllWhitespace from "   spa     .          nish  . txt  "

输出:"spa.nish.txt"


嗯?皮...?

简而言之:随机选择任何不是文本并且不太可能出现在文件名中的内容。如果有疑问:使用 pi ^ pi.

详细说明: 不要太纠结于pi:[=17的使用=] 在上面的分隔符列表中作为一个数量本身没有任何意义,它的唯一功能是作为 non-string 允许从文件名中删除列表中所有分隔符的实体,它将包括在 string-form 中出现的任何自身,即 "3.14159265359"。如果这个字符序列没有出现在文件名中,pi 可能是一个很好的选择来充当这个 "dummy delimiter"。否则,关键是将 pi 换成任何其他 non-string 值。说... pi + 1 ?我经常使用 nullmissing value 或 randomly-generated 数字。但是,如果您发现自己懒得生成数字或自己想一个数字,只需使用 pi ^ pi.