使用 AppleScript 将文件名中的无效字符替换为破折号
Replacing invalid characters in the filename with dashes using AppleScript
我的目标是使用 AppleScript 或 Javascript 在 Automator 中创建服务,它用破折号 (-
) 替换所选文件名 ()[\/:"*?<>|]+_
和空格的所有无效字符,并使文件名小写。
借助正则表达式和桥接到 AppleScriptObjC 的基础框架,这非常容易。
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
set fileName to "New(Foo)*aBcd<B|r.ext"
set nsFileName to current application's NSString's stringWithString:fileName
set nsLowerCaseFileName to nsFileName's lowercaseString()
set trimmedFileName to (nsLowerCaseFileName's stringByReplacingOccurrencesOfString:"[()[\/:\"*?<>|]+_]" withString:"-" options:(current application's NSRegularExpressionSearch) range:{location:0, |length|:nsLowerCaseFileName's |length|()}) as text
display dialog trimmedFileName
可以通过在您的 Automator 服务中使用 Bash Shell 脚本来替换 file/folder 名称中不允许的字符。
以下步骤描述了如何实现这一点:
配置 Automator
- 启动 Automator
- 键入 ⌘N,或从菜单栏中选择
File
> New
。
- Select
Service
然后点击 Choose
在 canvas 区域的顶部配置其设置如下:
Select Library
左上方panel/column:
在搜索字段中键入:获取 Select Finder 项目 并将 Get Select Finder items
操作拖到 canvas面积.
在搜索字段中键入:运行 Shell 并将 Run Shell Script
操作拖到 canvas 面积.
配置Run Shell Script
动作的顶部如下:
将以下 Bash 脚本添加到 Run shell Script
操作的主要区域:
#!/usr/bin/env bash
# The following characters are considered impermissible in a basename:
#
# - Left Square Bracket: [
# - Right Square Bracket: ]
# - Left Parenthesis: (
# - Reverse Solidus: \
# - Colon: :
# - Quotation Mark "
# - Single Quotation Mark '
# - Asterisk *
# - Question Mark ?
# - Less-than Sign <
# - Greater-than Sign >
# - Vertical Line |
# - Plus Sign +
# - Space Character
# - UnderScore _
#
# 1. Sed is utilized for character replacement therefore characters listed
# in the bracket expression [...] must be escaped as necessary.
# 2. Any forward slashes `/` in the basename are substituted by default with
# a Colon `:` at the shell level - so it's unnecessary to search for them.
#
declare -r IMPERMISSIBLE_CHARS="[][()\:\"'*?<>|+_ ]"
declare -r REPLACEMENT_STRING="-"
# Obtain the POSIX path of each selected item in the `Finder`. Input must
# passed to this script via a preceding `Get Selected Finder Items` action
# in an Automator Services workflow.
declare selected_items=("$@")
declare -a sorted_paths
declare -a numbered_paths
# Prefix the POSIX path depth level to itself to aid sorting.
for ((i = 0; i < "${#selected_items[@]}"; i++)); do
numbered_paths+=("$(echo "${selected_items[$i]}" | \
awk -F "/" '{ print NF-1, [=10=] }')")
done
# Sort each POSIX path in an array by descending order of its depth.
# This ensures deeper paths are renamed before shallower paths.
IFS=$'\n' read -rd '' -a sorted_paths <<< \
"$(printf "%s\n" "${numbered_paths[@]}" | sort -rn )"
# Logic to perform replacement of impermissible characters in a path basename.
# @param: {Array} - POSIX paths sorted by depth in descending order.
renameBaseName() {
local paths=("$@") new_basename new_path
for path in "${paths[@]}"; do
# Remove numerical prefix from each $path.
path="$(sed -E "s/^[0-9]+ //" <<< "$path")"
# Replaces impermissible characters in path basename
# and subsitutes uppercase characters with lowercase.
new_basename="$(sed "s/$IMPERMISSIBLE_CHARS/$REPLACEMENT_STRING/g" <<< \
"$(basename "${path}")" | tr "[:upper:]" "[:lower:]")"
# Concatenate original dirname and new basename to form new path.
new_path="$(dirname "${path}")"/"$new_basename"
# Only rename the item when:
# - New path does not already exist to prevent data loss.
# - New basename length is less than or equal to 255 characters.
if ! [ -e "$new_path" ] && [[ ${#new_basename} -le 255 ]]; then
mv -n "$path" "$new_path"
fi
done
}
renameBaseName "${sorted_paths[@]}"
Automator Service/Workflow 的已完成 canvas 区域现在应该如下所示:
键入 ⌘S,或从菜单栏中选择 File
> Save
。我们将文件命名为 Replace Impermissible Chars
.
运行启用服务:
在Finder中:
- Select一个单个文件或文件夹然后ctrl+点击显示上下文菜单
- Select上下文菜单中的
Replace Impermissible Chars
服务到运行它。
或者,在 Finder 中:
- Select 多个个文件and/or个文件夹,然后ctrl+单击 显示上下文菜单
- Select上下文菜单中的
Replace Impermissible Chars
服务到运行它。
备注:
Finder 将允许 运行 一次最多选择 1000 files/folders 个服务。
如果这是您创建的第一个 Automator 服务,您 可能(如果我没记错的话!)需要重新启动计算机才能使其成为通过上下文弹出菜单可用。
如果满足以下两个条件之一,Bash Shell 脚本将不会替换 file/folder 名称中不允许的字符:
如果 file/folder 名称已经存在,并且与生成的新 file/folder 名称相匹配。例如:假设我们有一个名为 hello-world.txt
的文件,在同一文件夹中有一个名为 hello?world.txt
的文件。如果我们 运行 hello?world.txt
上的服务,它的名称将不会是 corrected/changed,因为这可能会覆盖已经存在的 hello-world.txt
文件。
如果生成的文件名是>=
到255个字符。当然,只有当您将 REPLACEMENT_STRING
值(在 Bash/Shell 脚本中)更改为多个字符,而不只是一个连字符 -
.[=35= 时,才会发生这种情况]
这里有两个很好的解决方案。但由于每个问题通常都有很多解决方案,我提供另一个:
property alphabet : "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ"
--------------------------------------------------------------------------------
rename from "HELLO World+Foo(\"Bar\")new.ext"
--------------------------------------------------------------------------------
### HANDLERS
#
# rename from:
# Receives a text string and processes it for invalid characters, which
# get replaced with the specified replacement string (default: "-"),
# returning the result
to rename from filename given disallowed:¬
invalidCharSet as text : "[()[\/:\"*?<>|]+_] ", replaceWith:¬
replacementStr as text : "-"
local filename
local invalidCharSet, replacementStr
set my text item delimiters to {replacementStr} & ¬
the characters of the invalidCharSet
text items of the filename as text
makeLowercase(the result)
end rename
# makeLowercase():
# Receives a text string as input and returns the string formatted as
# lowercase text
to makeLowercase(str as text)
local str
set my text item delimiters to ""
if str = "" then return ""
set [firstLetter, otherLetters] to [¬
the first character, ¬
the rest of the characters] of str
tell the firstLetter to if ¬
it is "-" or ¬
it is not in the alphabet then ¬
return it & my makeLowercase(the otherLetters)
considering case
set x to (offset of the firstLetter in the alphabet) mod 27
end considering
return character x of the alphabet & my makeLowercase(the otherLetters)
end makeLowercase
此代码可用于 运行 AppleScript Automator 操作,将 rename from...
放在 on run {input, parameters}
处理程序,以及它之外的其余代码。它可以遵循向其提供 Finder 中的文件列表的操作,或者如果它是 运行 作为 [=21],它可以直接从工作流的输入中接收其输入=]服务.
property alphabet : "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ"
on run {input, parameters}
tell application "Finder" to repeat with f in input
set the name of f to (rename from f)
end repeat
end run
to rename from ...
.
.
end rename
to makeLowercase(str as text)
.
.
end makeLowercase
我的目标是使用 AppleScript 或 Javascript 在 Automator 中创建服务,它用破折号 (-
) 替换所选文件名 ()[\/:"*?<>|]+_
和空格的所有无效字符,并使文件名小写。
借助正则表达式和桥接到 AppleScriptObjC 的基础框架,这非常容易。
use AppleScript version "2.4" -- Yosemite (10.10) or later
use scripting additions
use framework "Foundation"
set fileName to "New(Foo)*aBcd<B|r.ext"
set nsFileName to current application's NSString's stringWithString:fileName
set nsLowerCaseFileName to nsFileName's lowercaseString()
set trimmedFileName to (nsLowerCaseFileName's stringByReplacingOccurrencesOfString:"[()[\/:\"*?<>|]+_]" withString:"-" options:(current application's NSRegularExpressionSearch) range:{location:0, |length|:nsLowerCaseFileName's |length|()}) as text
display dialog trimmedFileName
可以通过在您的 Automator 服务中使用 Bash Shell 脚本来替换 file/folder 名称中不允许的字符。
以下步骤描述了如何实现这一点:
配置 Automator
- 启动 Automator
- 键入 ⌘N,或从菜单栏中选择
File
>New
。 - Select
Service
然后点击Choose
在 canvas 区域的顶部配置其设置如下:
Select
Library
左上方panel/column:在搜索字段中键入:获取 Select Finder 项目 并将
Get Select Finder items
操作拖到 canvas面积.在搜索字段中键入:运行 Shell 并将
Run Shell Script
操作拖到 canvas 面积.
配置
Run Shell Script
动作的顶部如下:将以下 Bash 脚本添加到
Run shell Script
操作的主要区域:#!/usr/bin/env bash # The following characters are considered impermissible in a basename: # # - Left Square Bracket: [ # - Right Square Bracket: ] # - Left Parenthesis: ( # - Reverse Solidus: \ # - Colon: : # - Quotation Mark " # - Single Quotation Mark ' # - Asterisk * # - Question Mark ? # - Less-than Sign < # - Greater-than Sign > # - Vertical Line | # - Plus Sign + # - Space Character # - UnderScore _ # # 1. Sed is utilized for character replacement therefore characters listed # in the bracket expression [...] must be escaped as necessary. # 2. Any forward slashes `/` in the basename are substituted by default with # a Colon `:` at the shell level - so it's unnecessary to search for them. # declare -r IMPERMISSIBLE_CHARS="[][()\:\"'*?<>|+_ ]" declare -r REPLACEMENT_STRING="-" # Obtain the POSIX path of each selected item in the `Finder`. Input must # passed to this script via a preceding `Get Selected Finder Items` action # in an Automator Services workflow. declare selected_items=("$@") declare -a sorted_paths declare -a numbered_paths # Prefix the POSIX path depth level to itself to aid sorting. for ((i = 0; i < "${#selected_items[@]}"; i++)); do numbered_paths+=("$(echo "${selected_items[$i]}" | \ awk -F "/" '{ print NF-1, [=10=] }')") done # Sort each POSIX path in an array by descending order of its depth. # This ensures deeper paths are renamed before shallower paths. IFS=$'\n' read -rd '' -a sorted_paths <<< \ "$(printf "%s\n" "${numbered_paths[@]}" | sort -rn )" # Logic to perform replacement of impermissible characters in a path basename. # @param: {Array} - POSIX paths sorted by depth in descending order. renameBaseName() { local paths=("$@") new_basename new_path for path in "${paths[@]}"; do # Remove numerical prefix from each $path. path="$(sed -E "s/^[0-9]+ //" <<< "$path")" # Replaces impermissible characters in path basename # and subsitutes uppercase characters with lowercase. new_basename="$(sed "s/$IMPERMISSIBLE_CHARS/$REPLACEMENT_STRING/g" <<< \ "$(basename "${path}")" | tr "[:upper:]" "[:lower:]")" # Concatenate original dirname and new basename to form new path. new_path="$(dirname "${path}")"/"$new_basename" # Only rename the item when: # - New path does not already exist to prevent data loss. # - New basename length is less than or equal to 255 characters. if ! [ -e "$new_path" ] && [[ ${#new_basename} -le 255 ]]; then mv -n "$path" "$new_path" fi done } renameBaseName "${sorted_paths[@]}"
Automator Service/Workflow 的已完成 canvas 区域现在应该如下所示:
键入 ⌘S,或从菜单栏中选择
File
>Save
。我们将文件命名为Replace Impermissible Chars
.
运行启用服务:
在Finder中:
- Select一个单个文件或文件夹然后ctrl+点击显示上下文菜单
- Select上下文菜单中的
Replace Impermissible Chars
服务到运行它。
或者,在 Finder 中:
- Select 多个个文件and/or个文件夹,然后ctrl+单击 显示上下文菜单
- Select上下文菜单中的
Replace Impermissible Chars
服务到运行它。
备注:
Finder 将允许 运行 一次最多选择 1000 files/folders 个服务。
如果这是您创建的第一个 Automator 服务,您 可能(如果我没记错的话!)需要重新启动计算机才能使其成为通过上下文弹出菜单可用。
如果满足以下两个条件之一,Bash Shell 脚本将不会替换 file/folder 名称中不允许的字符:
如果 file/folder 名称已经存在,并且与生成的新 file/folder 名称相匹配。例如:假设我们有一个名为
hello-world.txt
的文件,在同一文件夹中有一个名为hello?world.txt
的文件。如果我们 运行hello?world.txt
上的服务,它的名称将不会是 corrected/changed,因为这可能会覆盖已经存在的hello-world.txt
文件。如果生成的文件名是
>=
到255个字符。当然,只有当您将REPLACEMENT_STRING
值(在 Bash/Shell 脚本中)更改为多个字符,而不只是一个连字符-
.[=35= 时,才会发生这种情况]
这里有两个很好的解决方案。但由于每个问题通常都有很多解决方案,我提供另一个:
property alphabet : "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ"
--------------------------------------------------------------------------------
rename from "HELLO World+Foo(\"Bar\")new.ext"
--------------------------------------------------------------------------------
### HANDLERS
#
# rename from:
# Receives a text string and processes it for invalid characters, which
# get replaced with the specified replacement string (default: "-"),
# returning the result
to rename from filename given disallowed:¬
invalidCharSet as text : "[()[\/:\"*?<>|]+_] ", replaceWith:¬
replacementStr as text : "-"
local filename
local invalidCharSet, replacementStr
set my text item delimiters to {replacementStr} & ¬
the characters of the invalidCharSet
text items of the filename as text
makeLowercase(the result)
end rename
# makeLowercase():
# Receives a text string as input and returns the string formatted as
# lowercase text
to makeLowercase(str as text)
local str
set my text item delimiters to ""
if str = "" then return ""
set [firstLetter, otherLetters] to [¬
the first character, ¬
the rest of the characters] of str
tell the firstLetter to if ¬
it is "-" or ¬
it is not in the alphabet then ¬
return it & my makeLowercase(the otherLetters)
considering case
set x to (offset of the firstLetter in the alphabet) mod 27
end considering
return character x of the alphabet & my makeLowercase(the otherLetters)
end makeLowercase
此代码可用于 运行 AppleScript Automator 操作,将 rename from...
放在 on run {input, parameters}
处理程序,以及它之外的其余代码。它可以遵循向其提供 Finder 中的文件列表的操作,或者如果它是 运行 作为 [=21],它可以直接从工作流的输入中接收其输入=]服务.
property alphabet : "abcdefghijklmnopqrstuvwxyz-ABCDEFGHIJKLMNOPQRSTUVWXYZ"
on run {input, parameters}
tell application "Finder" to repeat with f in input
set the name of f to (rename from f)
end repeat
end run
to rename from ...
.
.
end rename
to makeLowercase(str as text)
.
.
end makeLowercase