【问题标题】:How to grep umlauts and other accented text characters via AppleScript如何通过 AppleScript grep 变音符号和其他重音文本字符
【发布时间】:2018-03-28 12:57:15
【问题描述】:

我在尝试从 Apple 脚本执行 shell 脚本时遇到问题。我做了一个“grep”,但一旦它包含特殊字符,它就不能按预期工作。 (该脚本读取目录中的子文件夹列表并检查是否有任何子文件夹出现在文件中。)

这是我的脚本:

set searchFile to "/tmp/output.txt"

set theCommand to "/usr/local/bin/pdftotext -enc UTF-8 some.pdf" & space & searchFile
do shell script theCommand

tell application "Finder"
    set companies to get name of folders of folder ("/path/" as POSIX file)
end tell

repeat with company in companies
    set theCommand to "grep -c " & quoted form of company & space & quoted form of searchFile

    try
        do shell script theCommand
        set CompanyName to company as string
        return CompanyName
    on error

    end try
end repeat

return false

问题是例如带有变音符号的字符串。当我直接在 CLI 上执行时,“theCommand”的编码方式有所不同。

$ grep -c 'Württemberg' '/tmp/output.txt' --> typed on command line
3
$ grep -c 'Württemberg' '/tmp/output.txt' --> copy & pasted from AppleScript
0
$ grep -c 'rttemberg' '/tmp/output.txt'   --> no umlauts, no problems
3

第一行和第二行的“ü”不同; echo 'Württemberg' | openssl base64 显示了这一点。

我在不同的地方尝试了几种编码技巧,基本上我能找到或想到的一切。

有人知道吗?如何检查字符串的编码方式?

提前致谢! 塞巴斯蒂安

【问题讨论】:

  • /tmp/output.txt的内容是什么?它是否包括公司名称列表?您能否编辑您的问题以包括其内容及其示例。通过这样做,它可能会增加您获得合适答案的机会。只有变音符号会导致问题还是还有其他字符?
  • 感谢您的回答! output.txt 是一个转换后的 pdf 文件 - 我编辑了这篇文章。但是,我认为问题在于set theCommand to "grep -c '" & company... - 如果我用与公司相同的价值(但硬编码)替换“公司”,它就可以工作。例如。 set theCommand to "grep -c '" & "Baden-Württemberg" & "'" & space & 工作。
  • ß 也是一个问题。这些是德语特殊字符。
  • 请尝试set theCommand to "grep -c " & quoted form of company & space & quoted form of searchFile。 AppleScript 总是使用quoted form of 找到最佳报价。
  • 谢谢。我改变了它(并更新了最初的帖子) - 但仍然是同样的问题。

标签: grep applescript


【解决方案1】:

概述

这可以通过在 grep 命令中使用之前对每个 company 名称中具有重音符号的每个字符进行转义来实现。

因此,您需要使用双反斜杠(即\\)转义每个字符(即带有重音符号的字符)。例如:

  • Württemberg 中的ü 需要变为\\ü
  • Königsberg 中的 ö 需要变为 \\ö
  • Einbahnstraße 中的 ß 需要变为 \\ß

为什么需要这样做:

这些重音字符,例如u with diaeresis,肯定会以不同的方式编码。他们收到哪种类型的编码很难确定。我的假设是使用的编码模式以反斜杠开头 - 因此为什么用反斜杠转义这些字符可以解决问题。考虑上一个链接中带有分音符号的 u,它表明对于 C/C++ 语言,ü 被编码为 \u00FC


解决方案

在下面的完整脚本中,您会注意到以下内容:

  1. 已添加 set accentedChars to {"ü", "ö", "ß", "á", "ė"} 以保存需要转义的所有字符的列表。您需要明确说明每一个,因为似乎没有办法推断字符是否有口音。
  2. 在将grepcommand 分配给theCommand 变量之前,我们首先通过读取行​​来转义必要的字符:

    set company to escapeChars(company, accentedChars)
    

    正如您在此处看到的,我们将两个参数传递给 escapeChars 子例程(即非转义的 company 变量和重音字符列表)。

  3. escapeChars 子例程中,我们遍历accentedChars 列表中的每个char 并调用findAndReplace 子例程。这将使用company 变量中的反斜杠转义这些字符的任何实例。

完整的脚本:

set searchFile to "/tmp/output.txt"
set accentedChars to {"ü", "ö", "ß", "á", "ė"}

set theCommand to "/usr/local/bin/pdftotext -enc UTF-8 some.pdf" & ¬
  space & searchFile
do shell script theCommand

tell application "Finder"
  set companies to get name of folders of folder ("/path/" as POSIX file)
end tell

repeat with company in companies
  set company to escapeChars(company, accentedChars)

  set theCommand to "grep -c " & quoted form of company & ¬
    space & quoted form of searchFile

  try
    do shell script theCommand
    set CompanyName to company as string
    return CompanyName
  on error

  end try
end repeat

return false

(**
 * Checks each character of a given word. If any characters of the word
 * match a character in the given list of characters they will be escapd.
 *
 * @param {text} searchWord - The word to check the characters of.
 * @param {text} charactersList - List of characters to be escaped.
 * @returns {text} The new text with the item(s) replaced.
 *)
on escapeChars(searchWord, charactersList)
  repeat with char in charactersList
    set searchWord to findAndReplace(char, ("\\" & char), searchWord)
  end repeat
  return searchWord
end escapeChars

(**
 * Replaces all occurances of findString with replaceString
 *
 * @param {text} findString - The text string to find.
 * @param {text} replaceString - The replacement text string.
 * @param {text} searchInString - Text string to search.
 * @returns {text} The new text with the item(s) replaced.
 *)
on findAndReplace(findString, replaceString, searchInString)
  set oldTIDs to text item delimiters of AppleScript
  set text item delimiters of AppleScript to findString
  set searchInString to text items of searchInString
  set text item delimiters of AppleScript to replaceString
  set searchInString to "" & searchInString
  set text item delimiters of AppleScript to oldTIDs
  return searchInString
end findAndReplace

关于当前计数的说明:

目前,您的 grep 模式仅报告找到该单词的行数。不是找到该词的多少实例。

如果您想要单词的实际实例数,请使用带有grep-o 选项来输出每个出现的实例。然后使用-l 选项将其传送到wc 以计算行数。例如:

grep -o 'Württemberg' /tmp/output.txt | wc -l

在您的 AppleScript 中:

set theCommand to "grep -o " & quoted form of company & space & ¬
  quoted form of searchFile & "| wc -l"

提示:如果您想删除记录的计数/数字中的前导空格,请将其通过管道传送到 sed 以去除空格:例如通过您的脚本:

set theCommand to "grep -o " & quoted form of company & space & ¬
  quoted form of searchFile & "| wc -l | sed -e 's/ //g'"

以及通过命令行实现的等价物:

grep -o 'Württemberg' /tmp/output.txt | wc -l | sed -e 's/ //g'

【讨论】:

  • 哇。哇。非常感谢您花时间回答这个问题!这几乎令人难以置信。不仅仅是一个简单的“逃避你的角色”,而是一个完整的解决方案——甚至是关于 grepping 的评论......关于计数:是的,我知道这一点。我的用例非常数字化:它是否包含字符串(至少一次)。再一次非常感谢你!塞巴斯蒂安
  • 抱歉,由于帖子数量不足,无法为您的答案投票。
猜你喜欢
  • 1970-01-01
  • 2016-06-26
  • 1970-01-01
  • 1970-01-01
  • 2019-12-08
  • 2015-08-26
  • 2010-10-06
  • 1970-01-01
  • 2015-08-30
相关资源
最近更新 更多