вот и улетели в трубу очередные 2 дня на поиск причины бага
function SubString_Test1000 takes nothing returns nothing
local string s=""
local string s10="0123456789"
local string s100=s10+s10+s10+s10+s10+s10+s10+s10+s10+s10
local string s900=s100+s100+s100+s100+s100+s100+s100+s100+s100
local string s1100=s900+s100+s100
set s=SubString(s900,0,StringLength(s900))
call BJDebugMsg("900-0 "+SubString(s,StringLength(s)-10,StringLength(s))+" - "+I2S(StringLength(s)))
set s=SubString(s900,0,StringLength(s900)-1)
call BJDebugMsg("900-1 "+SubString(s,StringLength(s)-10,StringLength(s))+" - "+I2S(StringLength(s)))
set s=SubString(s1100,0,StringLength(s1100))
call BJDebugMsg("1100-0 "+SubString(s,StringLength(s)-10,StringLength(s))+" - "+I2S(StringLength(s)))
set s=SubString(s1100,0,StringLength(s1100)-1)
call BJDebugMsg("1100-1 "+SubString(s,StringLength(s)-10,StringLength(s))+" - "+I2S(StringLength(s)))
endfunction
set s=SubString(s,0,900-1) - нормально работает
set s=SubString(s,0,1100-1) - криво работает
близы только внесли путаницу со своими
set s4000=s1000+s1000+s1000+s1000
если у вас нативки не умеют работать со строками 1000-4000, то зачем вводить поддержку длинных строк и потом натыкаться на баги?
`
ОЖИДАНИЕ РЕКЛАМЫ...
14
ответ конечно же будет таким:
set s=SubString(s,0,>1000) - не работает
при этом забавно, что крит во время исполнения SubString не выдаётся, как это будет при загрузке карты с кодом set s="1100 знаков"
т.е. и не крит и не нормальная работа
в итоге - обязательно во все карты теперь надо вводить функцию разбивки длинных 4000 строк на 4 по 1000, чтобы без ошибок нормально можно было работать с ними
а при использовании юникодных кодировок (не англ язык) - вообще по 500 символов получится (по 1000 длине строки, но по 500 буков)
т.е. фактически макс длина строки даже не 1000/4000, а 500/2000
30
host_pi, по 500 символов получится если символ двухбайтовый, что неверно для китайского языка, там четыре байта. За смайлы я вообще молчу.
19
Я не заметил проблем при работе с длинными строками.
код
function Trig_test_Actions takes nothing returns nothing
local integer COUNT = 8
local string array strings
local integer i = 0
local string s = ""
	set strings[0] = "Lua is a powerful, efficient, lightweight, embeddable scripting language."
	set strings[1] = "It supports procedural programming, object-oriented programming, functional programming, data-driven programming, and data description."
	set strings[2] = "Lua combines simple procedural syntax with powerful data description constructs based on associative arrays and extensible semantics."
	set strings[3] = "Lua is dynamically typed, runs by interpreting bytecode with a register-based virtual machine, and has automatic memory management with a generational garbage collection, making it ideal for configuration, scripting, and rapid prototyping."
	set strings[4] = "Lua is implemented as a library, written in clean C, the common subset of standard C and C++."
	set strings[5] = "The Lua distribution includes a host program called lua, which uses the Lua library to offer a complete, standalone Lua interpreter, for interactive or batch use."
	set strings[6] = "Lua is intended to be used both as a powerful, lightweight, embeddable scripting language for any program that needs one, and as a powerful but lightweight and efficient stand-alone language."
	set strings[7] = "As an extension language, Lua has no notion of a \"main\" program: it works embedded in a host client, called the embedding program or simply the host."

	loop
		set s = s + strings[i]

		if i < (COUNT - 1) then
			set s = s + "\n"
		endif

		set i = i + 1
		exitwhen i >= COUNT
	endloop

	call BJDebugMsg("s length = " + I2S(StringLength(s)))
	call BJDebugMsg("«" + SubString(s, StringLength(s) - 20, StringLength(s)) + "»")
	call BJDebugMsg("«" + SubString(s, StringLength(s) - 10, StringLength(s)) + "»")
	call BJDebugMsg("«" + SubString(s, StringLength(s) - 10 - 1, StringLength(s) - 1) + "»")
endfunction

function InitTrig_test takes nothing returns nothing
    set gg_trg_test = CreateTrigger()
    call TriggerRegisterPlayerChatEvent(gg_trg_test, Player(0), "-test", true)
    call TriggerAddAction(gg_trg_test, function Trig_test_Actions)
endfunction
Вывод:
s length = 1182
« or simply the host.»
« the host.»
«y the host»
14
IceFog: Я не заметил проблем
если заменить
call BJDebugMsg
на
set s=SubString(s, StringLength(s) - 20, StringLength(s))
call BJDebugMsg(s)
то проблему можно увидеть
только вот вопрос - можно либо притворяться, что такой проблемы нет, либо открыто писать что она есть, но есть обходные пути

что, если у тебя УЖЕ есть готовая строка s - длиной 3500
и тебе нужно у неё обрезать последний символ?
при этом сохранив её в переменной, а не на экране в пропечатываемых 100 символах
как быть?
делить на 4 части по 1000, потом из последней отрезать , а потом опять сплюсовать s=s1+s2+s3+s4?
как это прекрасно, люблю жасы
особым бонусом будет смешанная строка из латиницы 1/1 + кириллицы 1/2 + иероглифов 1/4 - и сиди гадай, как бы тебе посередине иероглифа не разрезать во время попила на тысячные куски
хотя я уже днём это всё решил, это я так, бормочу после рутинного написания базовых функций, которые есть в нормальных языках
Загруженные файлы
19
если заменить
то проблему можно увидеть
	set slice = SubString(s, StringLength(s) - 20, StringLength(s))
	call BJDebugMsg("«" + slice + "»")
	set slice = SubString(s, StringLength(s) - 20 - 1, StringLength(s) - 1)
	call BJDebugMsg("«" + slice + "»")
« or simply the host.»
«m or simply the host»
Запись строки в переменную не повлияла на работоспособность.
Так же, я заглянул в нативки StringLength и SubString, но не обнаружил в них ограничений на длину строк.
Вместо этого, я обнаружил проблему при склейке строк оператором "+".
легендарный код
Третий параметр функций Copy и Cat отвечает за размер целевого буфера.
Локальная переменная занимает 4100 байт в стеке и вряд ли уместит в себе 2 гигабайта.
RCString *__stdcall CreateStringFromTwoBuffers(RCString *result, const char *a, const char *b)
{
    char buffer[4100]; // [esp+18h] [ebp-1008h] BYREF

    Storm_501_SStrCopy(buffer, a, 4097u);
    Storm_503_SStrCat(buffer, b, 0x7FFFFFFFu);
    RCString::ctor(result, buffer);
    return result;
}
14
IceFog: Запись строки в переменную не повлияла на работоспособность.
а ну да, я криво написал сверху
такое сработает:
	set slice = SubString(s, StringLength(s) - 20, StringLength(s)-1)
	call BJDebugMsg("«" + slice + "»")
а такое нет:
	set slice = SubString(s, 0, StringLength(s)-1)
	call BJDebugMsg("«" + slice + "»")
30
Так же, я заглянул в нативки StringLength и SubString, но не обнаружил в них ограничений на длину строк.
Кстати StringLength возвращает количество символов или байтов?
14
nazarpunk: StringLength возвращает количество символов или байтов?
call BJDebugMsg("privet - "+I2S(StringLength("privet")))
call BJDebugMsg("привет - "+I2S(StringLength("привет")))
call BJDebugMsg("priвет - "+I2S(StringLength("priвет")))
call BJDebugMsg("你好 - "+I2S(StringLength("你好")))
call BJDebugMsg("こんにちは - "+I2S(StringLength("こんにちは")))
call BJDebugMsg("안녕하세요 - "+I2S(StringLength("안녕하세요")))
call BJDebugMsg("☁❤♫✉ - "+I2S(StringLength("☁❤♫✉")))
возвращает количество символов/байтов после перевода из юникода в системный ANSI (тоже самое и с обрезкой)
я про это выше и писал при использовании мультиязыков в одном стринге (знаки препинания - то это англ)
иероглифы и смайлы кста по 3 а не по 4 занимают, англ 1, ру 2

вот например код из карты, когда картоделу приходится проверять локаль из чата и резать разным количеством, чтобы выполнить одну и ту же команду:
во второй -чатстроке сиди считай 1+3+3+3=10 при написании кода
	if SubString(s,0,6)=="-count" then
		call Command__CountMain(s,true)
	elseif SubString(s,0,10)=="-카운트" then
		call Command__CountMain(s,false)

function Command__CountMain takes string s,boolean Eng returns nothing
		if Eng==false then
			set time=S2I(SubString(s,11,13))
		else
			set time=S2I(SubString(s,7,9))
		endif
Загруженные файлы
19
Если копирование функцией SubString происходит начиная с первого байта, а хэши входной строки и результата совпадают, то может быть возвращена изначально переданая строка, вместо ожидаемой подстроки.
Разработчик функции решил не создавать копию подстроки в памяти, а вместо этого временно поставить нуль-терминатор посреди оригинальной строки, передать указатель на неё в конструктор нового объекта-строки, после чего вернуть буфер в исходный вид.
Но память, которую он временно модифицировал, принадлежала менеджеру строк и её нельзя было трогать
Проблема усугубляется тем, что StringHash обрабатывает только первые 1023 байта, так что любые две строки, учитываемый регион которых совпадает, имеют одинаковый хэш, что увеличивает вероятность бага на больших строках.
SubString
RCString *__thiscall RCString::create_slice(RCString *this, RCString *result, __int16 start, __int16 end)
{
  const char *chars; // eax MAPDST
  size_t chars_length; // eax
  __int16 end_validated; // cx
  char original_char; // bl
  char *p_slice_nt_position; // esi
  RCString temp; // [esp+14h] [ebp-18h] BYREF
  int _try_level; // [esp+28h] [ebp-4h]

  chars = RCString::c_str(this);
  if ( chars && (chars_length = Storm_506_SStrLen(chars)) != 0 && start <= (__int16)chars_length )
  {
    end_validated = end;
    if ( end >= (__int16)chars_length )
      end_validated = chars_length;
    original_char = chars[end_validated];
    p_slice_nt_position = (char *)&chars[end_validated];
    *p_slice_nt_position = 0;
    RCString::ctor(&temp, &chars[start]);
    *p_slice_nt_position = original_char;
    _try_level = 1;
    RCString::from(result, &temp);
    LOBYTE(_try_level) = 0;
    RCString::dtor(&temp);
  }
  else
  {
    RCString::from(result, &RCString::null);
  }
  return result;
}

int __cdecl Jass::Common::SubString(JassString *source, int start, int end)
{
  const char *chars; // eax
  int id; // esi
  RCString slice; // [esp+8h] [ebp-18h] BYREF
  int _try_level; // [esp+1Ch] [ebp-4h]

  RCString::create_slice(&source->string, &slice, start, end);
  _try_level = 0;
  chars = RCString::c_str(&slice);
  id = GetJassStringId(chars);
  _try_level = -1;
  RCString::dtor(&slice);
  return id;
}
Чтобы оставить комментарий, пожалуйста, войдите на сайт.