Comment gérer les trémas et autres caractères de texte accentués via AppleScript
J'ai un problème en essayant d'exécuter des scripts shell à partir d'un script Apple. Je fais un "grep", mais dès qu'il contient des caractères spéciaux cela ne fonctionne pas comme prévu. (Le script lit une liste de sous-dossiers ob dans un répertoire et vérifie si l'un des sous-dossiers apparaît dans un fichier.)
Voici mon script :
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
Le problème est par exemple avec les chaînes avec des trémas. "theCommand" est en quelque sorte codé différemment que lorsque je le fais directement sur la CLI.
$ 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
Les « ü » de la première et de la deuxième ligne sont différents ; a le echo 'Württemberg' | openssl base64
montre.
J'ai essayé plusieurs astuces d'encodage à différents endroits, essentiellement tout ce que je pouvais trouver ou penser.
Est-ce que quelqu'un a une idée? Comment puis-je vérifier l'encodage d'une chaîne ?
Merci d'avance! Sébastien
Aperçu
Cela peut fonctionner en échappant chaque caractère qui a un accent dans chaque company
nom avant qu'ils ne soient utilisés dans la grep
commande.
Ainsi, vous devrez échapper chacun de ces caractères (c'est-à-dire ceux qui ont un accent) avec des doubles barres obliques inverses (c'est-à-dire \\
). Par example:
- L'
ü
inWürttemberg
devra devenir\\ü
- L'
ö
inKönigsberg
devra devenir\\ö
- L'
ß
inEinbahnstraße
devra devenir\\ß
Pourquoi est-ce nécessaire :
Ces caractères accentués, comme un u avec tréma , sont certainement encodés différemment. Le type de codage qu'ils reçoivent est difficile à déterminer. Mon hypothèse est que le modèle d'encodage utilisé commence par une barre oblique inverse - c'est pourquoi l'échappement de ces caractères avec des barres obliques inverses résout le problème. Considérez le u avec tréma dans le lien précédent, cela montre que pour le langage C/C++ le ü
est encodé comme \u00FC
.
Solution
Dans le script complet ci-dessous, vous remarquerez les éléments suivants :
set accentedChars to {"ü", "ö", "ß", "á", "ė"}
a été ajouté pour contenir une liste de tous les caractères qui devront être échappés. Vous devrez indiquer explicitement chacun car il ne semble pas y avoir de moyen de déduire si le personnage a un accent.Avant d'affecter la
grep
commande à latheCommand
variable nous échappons d'abord les caractères nécessaires via la lecture de la ligne :set company to escapeChars(company, accentedChars)
Comme vous pouvez le voir ici, nous passons deux arguments à la
escapeChars
sous-routine, (c'est-à-dire lacompany
variable non échappée et la liste des caractères accentués).Dans le
escapeChars
sous-programme, nous parcourons chacunchar
de laaccentedChars
liste et invoquons lefindAndReplace
sous-programme. Cela échappera à toutes les instances de ces caractères avec des barres obliques inverses trouvées dans lacompany
variable.
Scénario complet :
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
Remarque sur les comptes actuels :
Actuellement, votre modèle grep ne rapporte que le nombre de lignes sur lesquelles le mot a été trouvé. Pas combien d'instances du mot ont été trouvées.
Si vous voulez le nombre réel d'instances du mot, utilisez l' -o
option avec grep
pour afficher chaque occurrence. Puis dirigez-le vers wc
avec la -l
possibilité de compter le nombre de lignes. Par example:
grep -o 'Württemberg' /tmp/output.txt | wc -l
et dans votre AppleScript ce serait :
set theCommand to "grep -o " & quoted form of company & space & ¬
quoted form of searchFile & "| wc -l"
Astuce : Si vous souhaitez supprimer les espaces de début dans le compte/nombre qui est enregistré, dirigez-le vers pour supprimer sed
les espaces : Par exemple via votre script :
set theCommand to "grep -o " & quoted form of company & space & ¬
quoted form of searchFile & "| wc -l | sed -e 's/ //g'"
et l'équivalent via la ligne de commande :
grep -o 'Württemberg' /tmp/output.txt | wc -l | sed -e 's/ //g'