Общее цитирование строки для TCL - PullRequest
17 голосов
/ 14 марта 2011

Я пишу утилиту (которая происходит в Python), которая генерирует вывод в виде сценария TCL.Учитывая некоторую произвольную строковую переменную (не unicode) в питоне, я хочу создать строку TCL, такую ​​как

set s something

..., которая установит переменную TCL 's' в эту точную строку, независимо откакие странные персонажи в нем.Не становясь слишком странным, я не хочу делать вывод более грязным, чем необходимо.Я считаю, что приличный подход -

  1. , если строка не пустая и содержит только буквенно-цифровые символы, а некоторые символы, такие как .-_ (но определенно не $"{}\), могут быть использованы как-is;

  2. , если он содержит только печатаемые символы и не содержит двойных кавычек или фигурных скобок (и не заканчивается обратной косой чертой), просто поместите вокруг него {};

  3. в противном случае поместите "" вокруг него после использования \ escape для " { } \ $ [ ] и \nnn escapeдля непечатаемых символов.

Вопрос: это полный набор символов, которые необходимо экранировать внутри двойных кавычек?Я не могу найти это в документах.И я что-то пропустил (я почти пропустил, что строки для (2) не могут заканчиваться, например, \).

Я знаю, что есть много других строк, которые можно заключить в кавычки {}, но, похоже,трудно их легко идентифицировать.Кроме того, похоже, что непечатные символы (в частности, новая строка) в порядке с (2), если вы не возражаете, что они буквально присутствуют в выводе TCL.

Ответы [ 3 ]

17 голосов
/ 14 марта 2011

Вам действительно нужно только 2 правила,

  • Escape фигурных скобок
  • Завернуть вывод в фигурные скобки

Вам не нужно беспокоиться о новых строках, непечатных символах и т. Д. Они действительны в виде буквенной строки, и TCL имеет отличную поддержку Unicode.

set s { 
this is
a 
long 
string. I have $10 [10,000 cents] only curly braces \{ need \} to be escaped.
\t is not  a real tab, but '    ' is. "quoting somthing" :
{matchin` curly braces are okay, list = string in tcl}
}

Редактировать В свете вашего комментария вы можете сделать следующее:

  • побег [] {} и $
  • Обернуть весь вывод в set s [subst { $output } ]

Прелесть Tcl в том, что она имеет очень простую грамматику. Других символов, кроме 3, необходимо экранировать.

Редактировать 2 Последняя попытка.

Если вы передадите subst некоторые опции, вам нужно будет только экранировать \ и {}

set s [subst -nocommands -novariables { $output } ]

Однако для преобразования непечатаемых символов в экранированные коды вам понадобится регулярное выражение.

Удачи!

6 голосов
/ 15 марта 2011

Tcl имеет очень мало метасимволов, как только вы внутри строки в двойных кавычках, и все они могут быть заключены в кавычки, поставив перед ними обратную косую черту. Символы, которые вы должны заключить в кавычки, - это \, $ и [, но рекомендуется также заключать в кавычки ], { и }, чтобы сам сценарий был встраиваемым. (Собственная команда Tcl list делает это, за исключением того, что она фактически не переносит двойные кавычки, поэтому она также обрабатывает обратную косую черту и пытается также использовать другие методы для «хороших» строк. Есть алгоритм для этого, но я советуем не беспокоиться о такой большой сложности в вашем коде; простые универсальные правила намного лучше для правильного кодирования.)

Второй шаг - получить данные в Tcl. Если вы генерируете файл, лучше всего записать его как UTF-8 и использовать опцию -encoding для команды tclsh / wish или для команды source для явного указания кодировки. (Если вы находитесь в одном и том же процессе, запишите данные UTF-8 в строку и оцените их. Задание выполнено.) Этот параметр (введенный в Tcl 8.5) специально предназначен для решения такой проблемы:

source -encoding "utf-8" theScriptYouWrote.tcl

Если это невозможно, вам придется вернуться к добавлению дополнительных цитат. Лучше всего тогда предположить, что у вас есть только доступная поддержка ASCII (хороший наименьший общий знаменатель) и процитировать все остальное как отдельный шаг к цитированию, описанному в первом абзаце . Чтобы заключить в кавычки, преобразуйте каждый символ Unicode от U + 00080 до escape-последовательности вида \uXXXX, где XXXX - ровно четыре шестнадцатеричных цифры [1] , а два других - буквенные символы. Не используйте форму \xXX, так как в ней есть некоторые «удивительные» ошибки (увы).


[1] В Tcl есть открытая ошибка, связанная с обработкой символов вне базовой многоязычной панели, часть которой заключается в том, что форма \u не может справиться. К счастью, не-BMP персонажи все еще достаточно редки на практике.

2 голосов
/ 14 марта 2011

Чтобы сделать это правильно, вы также должны указать кодировку, в которой находится строка вашего питона, обычно sys.getdefaultencoding (). В противном случае вы можете исказить кодировки при переводе на Tcl.

Если у вас есть двоичные данные в вашей строке и в результате вы хотите получить двоичные строки Tcl, это всегда будет работать:

data = "".join("\\u00%02x" % ord(c) for c in mystring)
tcltxt = "set x %s" % data

Хотя будет выглядеть как шестнадцатеричный дамп, но, ну, это шестнадцатеричный дамп ...

Если вы используете любую специальную кодировку, такую ​​как UTF-8, вы можете немного ее улучшить, используя кодировку convertfrom / convertto и соответствующую идиому Python.

data = "".join("\\u00%02x" % ord(c) for c in myutf8string)
tcltext = "set x [encoding convertfrom utf-8 %s]" % data

Конечно, вы можете немного уточнить это, избегая \ u-кодирования всех не специальных символов, но вышеприведенное безопасно в любом случае.

...