# Unicode строки в Instead
Frost(ping,10) — All
2020-09-21 15:14:58


Приветствую, друзья. Подскажите пожалуйста как можно работать с кириллицей в Instead. Я имею ввиду функции len; sub и другие, работающие с однобайтовой кодировкой символов. Имеет ли ядро движка встроенную поддержку и если да, то как получить доступ к UTF8 функциям. Если нет, подскажите наиболее оптимальную (проверенную) библиотеку для работы с юникодом. Заранее спасибо.
P.S. Edited: 2020-09-22 12:39:51 [изменено название]

# Re: UTF8 строки в Instead
hugeping(ping,1) — Frost
2020-09-21 19:03:05


> Приветствую, друзья. Подскажите пожалуйста как можно работать с кириллицей в Instead. Я имею ввиду функции len; sub и другие, работающие с однобайтовой кодировкой символов.

Привет!

На самом деле, в метапарсере есть такой код. Он написан на Lua. Но, в последней версии INSTEAD есть и C реализация, которая помогает этому Lua коду.

Наверное, проще всего посмотреть как это сделано в МП. Даю наводку: https://github.com/instead-hub/metaparser/blob/master/parser/mp.lua#L87

Функция, которая из строки делает массив литер.

Рядом есть более примитивные функции: utf_len, utf_char, utf_ff и utf_bb.

А вот как определяется, какую из реализаций брать -- на Lua или на C. Чтобы работало и со старым и с новым INSTEAD:

utf = {
    bb = std.rawget(_G, 'utf8_prev') or utf_bb;
    ff = std.rawget(_G, 'utf8_next') or utf_ff;
    len = std.rawget(_G, 'utf8_len') or utf_len;
    char = std.rawget(_G, 'utf8_char') or utf_char;
};

Прототипы функций если надо я могу вспомнить, но наверное есть смысл сначала посмотреть код, может быть там и так всё будет понятно. Навскидку:

utf_len, очевидно, возвращает число литер;
utf_char(строка, номер) - возвращает литеру по позиции;
utf_ff(строка, смещение) - возвращает смещение следующей литеры;
utf_bb(строка, смещение конца) - возвращает смещение предыдущей литеры;

# Re: Unicode строки в Instead
Frost(ping,10) — Frost
2020-09-22 13:04:52


Спасибо. Я благодарен за уделенное внимание моему вопросу. Однако на текущем этапе мне сложно разбираться в коде метапарсера. Многое в ответе мне не ясно, например вы говорите, что "в последней версии INSTEAD есть и C реализация"; или "А вот как определяется, какую из реализаций брать - на Lua или на C. Чтобы работало и со старым и с новым INSTEAD". Это меня приводит в замешательство. Поэтому я продолжал искал ответ, который будет мне понятен на моем уровне изучения LUA. Кое что мне удалось найти. Ниже приведу несколько ссылок для тех, кто как и я имеет начальный уровень знаний.

Статья "Могу ли я использовать строки Юникода? Lua поддерживает Юникод?" http://lua-users.org/wiki/LuaUnicode" (на английском) в конце статьи даны ссылки на разные библиотеки для работы с Юникодом. Для себя я выделил две:

https://github.com/alexander-yakushev/awesompd/blob/master/utf8.lua самый простой вариант и

https://github.com/wikimedia/mediawiki-extensions-Scribunto/tree/master/includes/engines/LuaCommon/lualib/ustring имеет больший функционал
P.S. Edited: 2020-09-22 13:09:07

Вытекающий вопрос: можно ли перевести Instead на работу с LUA версии 5.3, в которой есть встроенная поддержка Юникода?

# Re: Unicode строки в Instead
hugeping(ping,1) — Frost
2020-09-22 13:34:27


> Спасибо. Я благодарен за уделенное внимание моему вопросу. Однако на текущем этапе мне сложно разбираться в коде метапарсера.

Так там были готовые функции. Просто скопировать в свою игру.

local function utf_ff(b, pos)
	if type(b) ~= 'string' or b:len() == 0 then
		return 0
	end
	local utf8 = (std.game.codepage == 'UTF-8' or std.game.codepage == 'utf-8')
	if not utf8 then return 1 end
	local i = pos or 1
	local l = 0
	if b:byte(i) < 0x80 then
		return 1
	end
	i = i + 1
	l = l + 1
	while b:byte(i) and b:byte(i) >= 0x80 and b:byte(i) <= 0xbf do
		i = i + 1
		l = l + 1
		if i > b:len() then
			break
		end
	end
	return l
end

local function utf_chars(b)
	local i = 1
	local s
	local res = {}
	local ff = std.rawget(_G, 'utf8_next') or utf_ff
	while i <= b:len() do
		s = i
		i = i + ff(b, i)
		table.insert(res,  b:sub(s, i - 1))
	end
	return res
end

Вот это реализация utf_chars, которая сделает массив с литерами из строки:

local a = utf_chars("привет")

Мне просто неизвестно, какие функции нужны.

> Вытекающий вопрос: можно ли перевести Instead на работу с LUA версии 5.3, в которой есть встроенная поддержка Юникода?

ИНСТЕД и так работает (может быть собран) с Lua от 5.1 до 5.4. Но если нужно, чтобы игра работала на всех видах установок (не только на собственной версии), нужно пользоваться 5.1. В основном это связано с тем, что бинарные сборки используют LuaJit, который 5.1 (с расширениями).

# Re: Unicode строки в Instead
Frost(ping,10) — hugeping
2020-09-22 14:17:47


Огромное спасибо за оперативную помощь! Мне ваши ответы действительно помогли. При анализе кода
local utf8 = (std.game.codepage == 'UTF-8' or std.game.codepage == 'utf-8')

выяснилось, что std.game приводит к ошибке. Мне пришлось удалить фрагмент

local utf8 = (std.game.codepage == 'UTF-8' or std.game.codepage == 'utf-8')
if not utf8 then return 1 end

Файл с кодом игры ведь обязан быть в кодировке UTF-8 (разве не так?). Зачем тогда эта проверка?

# Re: Unicode строки в Instead
hugeping(ping,1) — Frost
2020-09-22 14:36:39


> выяснилось, что std.game приводит к ошибке. Мне пришлось удалить фрагмент

Файл с игрой называется main3.lua или main.lua? Нужно, чтобы было main3.lua -- это новое INSTEAD API, старое API больше не поддерживается.

> Файл с кодом игры ведь обязан быть в кодировке UTF-8 (разве не так?). Зачем тогда эта проверка?

Формально, не обязан. Дело в том, что до сих пор есть поддержка разных кодировок, но по факту -- никто кроме utf-8 ничего не использует. И это хорошо.

# Re: Unicode строки в Instead
Frost(ping,10) — hugeping
2020-09-22 14:54:41


Файл с игрой называется main3.lua
P.S. Edited: 2020-09-22 14:59:01

Содержимое файла main3.lua

require 'sprite'
sprite.direct(true)
print(std.game.codepage)

# Re: Unicode строки в Instead
hugeping(ping,1) — Frost
2020-09-22 15:00:55


> print(std.game.codepage)

Конечно, так не сработает, в этот момент game ещё нет. Но в моём коде std.game проверяется внутри функции, запуск которой предполагается в момент, когда игра уже запущена. Например, в start() и позже...