Ссылаясь на сообщение Рохо на https://stackoverflow.com/a/15032476/3627676
Определенно, его решение - это то, что я ищу в течение небольшого времени (конечно, я мог бы попытаться реализовать что-то похожее на это, но лень двигает прогрессом :)). Одна вещь, которую я хотел бы добавить, - это небольшое улучшение исходного кода. Я думал, что было бы лучше, если бы перенаправление в файл было написано в конце строки. В этом случае линия стартера heredoc может быть более строгой, а ее анализ - более простым.
@echo off
set "hello=Hello world!"
set "lorem=Lorem ipsum dolor sit amet, consectetur adipiscing elit."
call :heredoc HTML & goto :HTML
!hello!
Variables in heredoc should be surrounded by the exclamation mark (^!).
!lorem!
Exclamation mark (^!) and caret (^^) MUST be escaped with a caret (^^).
:HTML
goto :EOF
:: https://stackoverflow.com/a/15032476/3627676
:heredoc LABEL
setlocal enabledelayedexpansion
set go=
for /f "delims=" %%A in ( '
findstr /n "^" "%~f0"
' ) do (
set "line=%%A"
set "line=!line:*:=!"
if defined go (
if /i "!line!" == "!go!" goto :EOF
echo:!line!
) else (
rem delims are ( ) > & | TAB , ; = SPACE
for /f "tokens=1-3 delims=()>&| ,;= " %%i in ( "!line!" ) do (
if /i "%%i %%j %%k" == "call :heredoc %1" (
set "go=%%k"
if not "!go:~0,1!" == ":" set "go=:!go!"
)
)
)
)
goto :EOF
Что я предлагаю этим кодом? Давайте рассмотрим.
Код Рохо очень строг:
call
и :heredoc
call :heredoc
привязан к краю строки (без пробелов в начале строки) Вещи, которые я предлагаю:
Обновление 1 : улучшения в проверке и выполнении начала heredoc:
call :heredoc LABEL
или call :heredoc :LABEL
. Таким образом, после распечатки содержимого heredoc можно перейти к другой метке, концу сценария или запустить exit /b
. Обновление 2 :
for
являются (
)
>
&
|
TAB
,
;
=
SPACE
/I
добавлен в if
Обновление 3 :
По следующей ссылке вы можете найти полную версию автономного скрипта (встраивание в ваши скрипты доступно) https://github.com /ildar-shaimordanov/tea-set/blob/master/bin/heredoc.bat
У меня есть собственное решение для этого:
public class Randomizator3000
{
public class Item<T>
{
public T value;
public float weight;
public static float GetTotalWeight<T>(Item<T>[] p_itens)
{
float __toReturn = 0;
foreach(var item in p_itens)
{
__toReturn += item.weight;
}
return __toReturn;
}
}
private static System.Random _randHolder;
private static System.Random _random
{
get
{
if(_randHolder == null)
_randHolder = new System.Random();
return _randHolder;
}
}
public static T PickOne<T>(Item<T>[] p_itens)
{
if(p_itens == null || p_itens.Length == 0)
{
return default(T);
}
float __randomizedValue = (float)_random.NextDouble() * (Item<T>.GetTotalWeight(p_itens));
float __adding = 0;
for(int i = 0; i < p_itens.Length; i ++)
{
float __cacheValue = p_itens[i].weight + __adding;
if(__randomizedValue <= __cacheValue)
{
return p_itens[i].value;
}
__adding = __cacheValue;
}
return p_itens[p_itens.Length - 1].value;
}
}
И его использование должно быть примерно таким (вот в Unity3d)
using UnityEngine;
using System.Collections;
public class teste : MonoBehaviour
{
Randomizator3000.Item<string>[] lista;
void Start()
{
lista = new Randomizator3000.Item<string>[10];
lista[0] = new Randomizator3000.Item<string>();
lista[0].weight = 10;
lista[0].value = "a";
lista[1] = new Randomizator3000.Item<string>();
lista[1].weight = 10;
lista[1].value = "b";
lista[2] = new Randomizator3000.Item<string>();
lista[2].weight = 10;
lista[2].value = "c";
lista[3] = new Randomizator3000.Item<string>();
lista[3].weight = 10;
lista[3].value = "d";
lista[4] = new Randomizator3000.Item<string>();
lista[4].weight = 10;
lista[4].value = "e";
lista[5] = new Randomizator3000.Item<string>();
lista[5].weight = 10;
lista[5].value = "f";
lista[6] = new Randomizator3000.Item<string>();
lista[6].weight = 10;
lista[6].value = "g";
lista[7] = new Randomizator3000.Item<string>();
lista[7].weight = 10;
lista[7].value = "h";
lista[8] = new Randomizator3000.Item<string>();
lista[8].weight = 10;
lista[8].value = "i";
lista[9] = new Randomizator3000.Item<string>();
lista[9].weight = 10;
lista[9].value = "j";
}
void Update ()
{
Debug.Log(Randomizator3000.PickOne<string>(lista));
}
}
В этом примере каждое значение имеет Вероятность 10% будет отображаться как отладка = 3
Кнут ссылается на псевдонимы Уокера. Поиск по этому, я нахожу http://code.activestate.com/recipes/576564-walkers-alias-method-for-random-objects-with-diffe/ и http: // prxq.wordpress.com/2006/04/17/the-alias-method/. Это дает точные вероятности, требуемые в постоянном времени для числа, сгенерированного с линейным временем для настройки (любопытно, что n log n время для настройки, если вы используете точно метод, описанный Кнутом, который делает подготовительную сортировку, которую вы можете избежать).