Как считать из реестра значение параметра, который имеет тип REG_EXPAND_SZ?

kravam

Друзья! Тип REG_EXPAND_SZ в реестре это очень хитрый тип,называется "Расширяемый строковый параметр". То есть он может быть строкой и двоичными данными одновременно. Вот такой у меня параметр типа REG_EXPAND_SZ был в реестре.
43 00 50 00 00 00 6C D9
Что говорит о типе REG_EXPAND_SZ питон? А вот что:winreg.REG_EXPAND_SZ Null-terminated string containing references to environment variables (%PATH%).Что это значит? А это значит, что при правильном (как у меня) преобразовании этого параметра в строку, интерпретатор будет считывать символы до тех пор, пока не наткнётся на два ноля подряд, что будет являться концом строки! И получим строку "CP" (\u0043 и \u0043). Так, а у меня интерпретатор вместо того, чтобы остановиться на \u0000 лезет дальше, считывает \uD96C, а это суррогатная пара и получаем ругань.+++++++++++++++++++++++++++++++++++++++++++Вот как я считываю этот параметр:
import winreg
 
#откроем раздел
key_reg = winreg.OpenKey(winreg.HKEY_CLASSES_ROOT, "foo")
 
#откроем получим даные о первом и единственном параметре в этом ключе
t = winreg.EnumValue(key_reg, 0)
 
#ну и выведем эти даные, сперва имя
print(t[0])
 
#и значение, кстати, t [1] имеет тип str
print(t[1])
Получаем ругань:
    print(t[1])
UnicodeEncodeError: 'utf-8' codec can't encode character '\ud96c' in position 3: surrogates not allowed
...прежде, чем выходить из положения, вручную ища в строке два подряд идущих ноля, хочется спросить- да как так-то, он же сам пишет в документации, что строка должна оканчиваться нолём, а при считывании этот ноль пропускает и лезет дальше Может, я что не так делаю? Содержание *.reg-файла прилагается, если кто будет экспериментировать. Спасибо, кто откликнется. python 3.3, XP Home 32 SP3
Windows Registry Editor Version 5.00[HKEY_CLASSES_ROOT\foo] "bar"=hex(2):43,00,50,00,00,00,6c,d9
9 ответов

kravam

попробовал на своем python 3.6.1, ошибок нет, но выводит bar CP


kravam

попробовал на своем python 3.6.1, ошибок нет, но выводит bar CP
Везёт. А у меня максимальная версия. которая может встать это 3.4.4Ещё соображений, ребята.


kravam

на python 3.3.5 вывод немного другой: bar CP [символ квадратика]


kravam

интерпретатор вместо того, чтобы остановиться на \u0000 лезет дальше, считывает \uD96C,
Все правильно он считывает - до самых последних 00 00 (то есть все это 43,00,50,00,00,00,6c,d9 а дальше 00 00). А то что у вас в реестре в строке зачем то суррогатная пара - не проблема интерпретатора. Любые другие параметры типа REG_EXPAND_SZ считываются корректно.


kravam

Все правильно он считывает - до самых последних 00 00 (то есть все это 43,00,50,00,00,00,6c,d9 а дальше 00 00). А то что у вас в реестре в строке зачем то суррогатная пара - не проблема интерпретатора. Любые другие параметры типа REG_EXPAND_SZ считываются корректно.
Он считывает как считывает. Тут нет какого-то стандарта на считывание, как я понял. Я вот, например, не считаю считывание до ПОСЛЕДНИХ ДВУХ нолей правильным. А считаю правильным считывание до ПЕРВЫХ ДВУХ нолей.Вы удивитесь, но разработчики интерпретатора со мной согласны. Правда, спохватились они поздно и сделали считывание правильным, как сказал pashtet-kun, в версии 3.6.1. Поэтому допускаем. что такая же возможность реализована и в версии 3.3.5, просто она неявна и её нужно найти.


kravam

А считаю правильным считывание до ПЕРВЫХ ДВУХ нолей. Вы удивитесь, но разработчики интерпретатора со мной согласны
Ничего подобного. И разрабы python'а никакого отношения не имеют к тому как требуется считывать параметры из реестра windows. Как в microsoft определили - так и считывают.
не считаю считывание до ПОСЛЕДНИХ ДВУХ нолей правильным
Тикет в microsft :-)Что касается ошибок декодирования в данном случае - то это ошибки вывода в консоль cmd. Опять же они никакого отношения не имеют к реестру windows и считыванию оттуда каких либо параметров. Что касается версии 3.6 python - в этой версии просто поправили вывод юникода в консоль cmd. Это не значит, что решились все проблемы. Это значит что теперь нет этих дурацких сообщений об ошибках декодирования при печати- символ либо выводится, либо нет (квадратик).


kravam

Garry Galler, kravam прав: Issue #25778: winreg does not truncase string correctly issue25778 В предыдущих версиях единственное что интерпритатор делает с предоставляемой ему винайпишной функцией строкой - удаляет конечный ноль, если он есть, при этом предыдущая часть строки может содержать сколько угодно нулей и чего угодно другого (утрирую, конечно, но тем не менее). В 3.6.1 строка обрезается по первому встретившемуся нулю (юникодному), отбрасывая оставшийся хвост.


kravam

Что-то я ещё больше запутался.shsv, скажите пожалуйста, я вот прошёл по вашей второй ссыли и сделал такой вывод: в python версии 3.6 и 3.7 был замечен баг, заключающийся в неправильном обрезании строкового параметра (наверное, по первым двум встреченным нолям.) И теперь он решён теперь в дальнейших версиях (3.8 и т.д) интерпретатор снова будет считывать ВСЁ. Или как там можно понять?


kravam

Наоборот. Поправить поведение интерпритатора собирались ещё год назад (т.е. в ветке 3.5 и 2.7 до кучи), но почему-то все ответственные люди забыли закомитить это дело. На целый год. Пока их не пнул возмущенный пользователь. В итоге патч успел попасть только в 3.6.1. Решили также, что поведение всех прочих версий изменяться не будет, т.е. версии 3.6.1 и выше будут резать строку по первому нулю, все младшие версии, как и прежде, допускают строки с вложенными нулями. (Кстати веской причиной принятия патча послужило поведение regedit, который не смотря на то что допускает создание строк с нулями внутри, при отображении режет их по первому)