在批处理中,我可以创建一行显示的文本,当它转到新行时不会分开单词吗?

时间:2014-01-06 05:43:01

标签: windows batch-file

我正在编写一个相当复杂的批处理文件,用于创建D& D字符。部分内容涉及显示长句子,在指定的窗口宽度之后,程序将分开单词并将切断的部分固定到下一行。无论如何只是让它推动将被分割到下一行的词?

3 个答案:

答案 0 :(得分:4)

下面的批处理文件是单词程序的基本换行。

@echo off
setlocal EnableDelayedExpansion

rem Get the window width
for /F "skip=4 tokens=2 delims=:" %%a in ('mode con') do set /A width=%%a-1 & goto continue
:continue

rem Read the file given by first param and show its contents with no word split

set "output="
rem For each line in input file
for /F "delims=" %%a in (%1) do (
   rem For each word in input line
   for %%b in (%%a) do (
      rem Add the new word
      set "newOutput=!output! %%b"
      rem If new word don't exceed window width
      if "!newOutput:~%width%,1!" equ "" (
         rem Keep it
         set "output=!newOutput!"
      ) else (
         rem Show the output before the new word
         echo !output!
         rem and store the new word
         set "output=%%b"
      )
   )
)
rem Show the last output, if any
if defined output echo !output!

您可以修改此批处理文件以满足您的特定需求。请注意,此程序可能会遇到特殊批处理字符的问题,但这些问题可能会得到解决。

答案 1 :(得分:2)

@ECHO OFF
SETLOCAL
:: This sets up %lines% and %columns% in use
FOR /f "tokens=1,2delims=: " %%a IN ('mode con:') DO IF NOT "%%b"=="" SET /a %%a=%%b

:: FOR TESTING PURPOSES, set LINES and COLUMNS
ECHO lines and columns found= %lines% and %columns%
SET /a lines=10, columns=40
ECHO lines and columns FORCED= %lines% and %columns%
pause

:: I'll read from a textfile for convenience. Any text required needs just CALL :OUTPUT text to display
:: But let's clear the screen to start...
CALL :clsnp
SET "remainder="
FOR /f "delims=" %%a IN (q20943733.txt) DO (
 CALL :OUTPUT %%a
)
GOTO :EOF

:: :clsnp to clear screen then new page
:: :newpage to continue to a new page

:clsnp
cls
:newpage
SET /a linesleft=%lines% - 1
GOTO :eof

:: Output some text

:output
SET "remainder=%*"
SET remainder=%remainder:"=%
:outloop
SET /a lastsp=%columns% - 1
CALL :splitline
ECHO(%line%
SET /a linesleft -=1
IF %linesleft% leq 0 (pause&CALL :newpage)
IF DEFINED remainder GOTO outloop
GOTO :eof

:splitline
SET /a lastsp-=1
CALL SET line=%%remainder:~%lastsp%,1%%
IF NOT DEFINED line SET line=%remainder%&SET "remainder="&GOTO :EOF
IF NOT "%line%"==" " GOTO splitline
CALL SET line=%%remainder:~0,%lastsp%%%
SET /a lastsp+=1
CALL SET remainder=%%remainder:~%lastsp%%%
GOTO :eof

嗯,这是一个有趣的问题 - 并且警告 - 批处理有一些问题,如%^&|<>处理某些字符,所以基本上 - 避免它们。

使用@echo offsetlocal(或setlocal enabledelayedexpansion

启动批处理是正常的

::开头的行是注释。 ::是非正式的,但是常用且比REM更少侵入性。当然,评论可以省略 - 但是当你以后维护你的工作时,它也会很有用。

第一个FOR循环建立了一些变量,最重要的是LINESCOLUMNS,以便批处理可以计算所需的宽度和页面长度。

接下来的几行仅用于测试目的。我的控制台设置为780行和171列,所以我显示了找到的值,然后强制他们故意小值以测试例程。如果您愿意,可以删除该代码块,但如果您只是将其注释掉,则可以轻松更改为自己的测试强制执行的值。

下一步是清除屏幕并初始化页面左侧的行数。你需要做的只是CALL :clsnp如果你只是想重新启动一个“页面”(例如,在提示回复之后)CALL :newpage(比重复{{更容易和更好理解) 1}})

接下来,我只使用名为SET的文本文件中的随机文本作为要输出和格式化的字符串。

输出非常简单。只需q20943733.txtCALL :OUTPUT Some text to be output或甚至CALL :OUTPUT %variable%CALL :OUTPUT You have %hitpoints% hitpoints and %gold% gold pieces例程就可以格式化文字,从而打破单词之间的界限。如果需要的话。

OUTPUT

会显示这三个特征 - 它可能比CALL :OUTPUT Strength %strength% CALL :output Hitpoints %hitpoints% call :output %gold% gold pieces

更容易阅读

例程ECHO以后的例程可能最好放在批处理的末尾。您只需要用游戏机制替换文本文件的读取......

最后一点小提示:这是一个有用的例程:

:clsnp

如果您然后编码:getresponse set "response=" set /p response="%* " if defined response goto :eof goto getresponse ,那么您将收到提示CALL :getresponse Which direction ?,当例程返回时,Which direction ?将提供用户的响应...

答案 2 :(得分:0)

我接受了Magoo的答案并进行了扩展,部分原因是我对如何使用他感到有些困惑,部分是因为它存在一些问题(主要是特殊字符,例如&符),部分是为了添加更多功能。这都是我正在编写的更大脚本的一部分,而我只是在玩弄它并学习东西。我想强调一下,这是建立在Magoo的工作之上的,没有它,我不确定我是否能够弄清楚该怎么做(他的代码仍然是核心,负责实际包装),当然也可以会花更长的时间。长度确定函数的代码来自jeb的答案here,我对其稍作修改以处理特殊字符,因为他的代码会将计数减一(我在那儿会提到,但不能因为它已关闭,由于权限不足,我无法发表评论)。该代码已被大量注释,因此在此我将不做任何解释。只需将其全部放在代码的其余部分之后或放在单独的批处理文件中(尽管我没记错,这会给您的调用方式带来一些复杂性)。如前所述,我无法发表评论,因此,如果您有任何疑问,除非该规则不适用于您自己的答案,否则我将无法回复。无论如何,我希望这对某人有帮助。

REM  Function to determine length of string passed to it. Needs to be placed after primary script code.
:length
setlocal EnableDelayedExpansion
SET STR=%*
REM  Change any ampersands in input to ASCII placeholder so function can process it
SET "STR=!STR:&=!"
REM  Remove triple-quotes from input since quotes are needed to pass ampersands (and possibly other characters) to the function for it to work properly, but may not be desired in final output, so using triple-quotes will allow them to be used but not displayed
SET "STR=!STR:"""=!"
rem !FOR %%a IN (%*) DO SET STR=!STR! %%a
rem !FOR /F "tokens=* delims= " %%a IN ("!STR!") DO SET STR=%%a
SET STR_REMAINDER=!STR!

SET /A STR_LEN=0
FOR %%p IN (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) DO (
  If NOT "!STR_REMAINDER:~%%p,1!" == "" ( 
    SET /A STR_LEN+=%%p
    SET "STR_REMAINDER=!STR_REMAINDER:~%%p!"
  )
)
REM  Add 1 to counted length since it doesn't check "!STR_REMAINDER:~0,1!" which would check for a single character, and doing so wouldn't help since it would just add 0 (%%p) and therefore not change the count
SET /A STR_LEN+=1

endlocal & SET /A STR_LEN=%STR_LEN%
exit /b

REM  Function to center text passed to it. Needs to be placed after primary script code. Use :centerwrap function; this function will be called from there.
:center
setlocal EnableDelayedExpansion
SET STR=%*
REM  Change any ampersands in input to ASCII placeholder so function can process it
SET "STR=!STR:&=!"
REM  Remove ASCII character used to retain leading spaces (indent)
SET "STR=!STR:=!"
REM  Remove triple-quotes from input since quotes are needed to pass ampersands (and possibly other characters) to the function for it to work properly, but may not be desired in final output, so using triple-quotes will allow them to be used but not displayed
SET "STR=!STR:"""=!"
SET STR_REMAINDER=!STR!

SET /A STR_LEN=0
FOR %%p IN (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) DO (
  If NOT "!STR_REMAINDER:~%%p,1!" == "" ( 
    SET /A STR_LEN+=%%p
    SET "STR_REMAINDER=!STR_REMAINDER:~%%p!"
  )
)
REM  Add 1 to counted length since it doesn't check "!STR_REMAINDER:~0,1!" which would check for a single character, and doing so wouldn't help since it would just add 0 (%%p) and therefore not change the count
SET /A STR_LEN+=1

REM  Set base offset by subtracting half of STR_LEN from half of columns (midpoint of window width)
SET /A OFFSET="( !COLUMNS! / 2 ) - ( !STR_LEN! / 2 )"

REM  Set variable to determine whether to shift lines that don't center exactly one space to the left or to the right. If # of columns AND string length are even or odd it will center exactly, but if column # is even and string length is odd, line will be off-center slightly to the right, and if column # is odd and string length is even line will be off-center slightly to the right, so this will either tell the function to shift to the left in the prior case or to the right in the latter.
SET SHIFT=LEFT

REM  Determine if window columns (width) # is even or odd
SET /A COL_1="( !COLUMNS! / 2 ) * 10"
SET /A COL_2="( !COLUMNS! * 10 ) / 2"
If !COL_1! equ !COL_2! (
  SET COLS=EVEN
) Else (
  SET COLS=ODD
)

REM  Determine if string length is even or odd and use that and whether column number is even or odd to determine offset
SET /A STR_LEN_1="( !STR_LEN! / 2 ) * 10"
SET /A STR_LEN_2="( !STR_LEN! * 10 ) / 2"

If !STR_LEN_1! equ !STR_LEN_2! (
  REM  String length is even
  If "!COLS!" == "ODD" (
    If /I "!SHIFT!" == "RIGHT" (
      SET /A OFFSET+=1
    )
  )
) Else (
  REM  String length is odd
  If "!COLS!" == "EVEN" (
    If /I "!SHIFT!" == "LEFT" (
      SET /A OFFSET-=1
    )
  )
)

REM  Create variable full of spaces then create variable combining only the first !OFFSET! characters (spaces) followed by the text to be displayed, then echo the variable to display the resultant centered text
SET "SPACES=                                                                                                                                                                                                                                 "
SET "CENTERED_STR=!SPACES:~0,%OFFSET%!%STR%"
REM  Change ASCII placeholders assigned earlier back to " and & before output is displayed
SET "CENTERED_STR=!CENTERED_STR:="!"
SET "CENTERED_STR=!CENTERED_STR:=&!"
echo !CENTERED_STR!
endlocal
exit /b

REM  Function to display text passed to it and word-wrap it so newlines occur on spaces and not mid-word. Needs to be placed after primary script code. To use type "call :function_name [x] [y] [Text to be wrapped]" (without the quotes or brackets), x and y are parameters for use only in indent and justify functions. All functions run through :wrap and therefore perform the basic word-wrap function. To pass spaces at the beginning of the string through, use a dot (.) as the first character (e.g. "call :wrap .      text" or "call :hangjustify 15 5 .        text"). This is necessary to have the spaces included since these functions use the call parameters as input and therefore don't see anything until the first non-space character. The dot will simply be removed and the spaces will be retained. It's not necessary to do this for functions that call the param_check_and_trim function (those with x/y variables), but there is no harm in doing so. Note that certain characters may not be able to be passed to these functions (e.g. ^ will be ignored, though that could theoretically be changed if desired). Quotes (") and parentheses are fine, however, and closing parentheses don't need to be escaped unless inside an if statement, just like with echo, i.e. (text^), and can simply be entered normally, i.e. (text), though escaping them won't affect anything as carets are removed. Ampersands (&) can also be used, though if the text sent to the functions contains any it needs to be wrapped in quotes (e.g. call :wrap "Foo & bar" -> "Foo & bar" // call :wrap Foo "&" bar -> Foo "&" bar). This means that if any variables that may possibly contain any ampersands are included in the call, the line OR variable(s) should be wrapped in quotes, otherwise it will not return any output if any are present. In order to do this without displaying the quotes in the final output, wrap the text in triple quotes (e.g. call :wrap """Foo & bar""" OR call :wrap Foo """&""" bar -> Foo & bar). If the entire line is quoted to allow for ampersands, no text within the line can be quoted (e.g. """Foo & "bar"""" wouldn't work; however, Foo """&""" "bar" would). Caution is needed with parameters containing quotes, such as a quoted path\filename set to a variable, such as would occur if passing a path\filename to another function and setting it to a variable there, then including the variable in a call to these functions, as the quotes will be counted. This means using the standard single or triple quotes would result in double or quadruple quotes, which will result in no output. In these cases, either the quotes must be stripped from the variable or the quotes used in the call to these functions must be adjusted (subtract one to account for set in variable, so " -> none and """ -> ""). Also be aware the output is much slower than simply echo'ing the lines, and therefore will impart a *very* slight delay in displaying each line, making the functions undesirable or even unsuitable for certain tasks, like frequent screen refreshing, e.g. if implementing a timer. Note that a "full/equalwrap" function to try and split text evenly across all lines, to for example create somewhat shorter but more even lines vs longer lines with the last one being shorter than the rest, was considered and attempted, but this is likely not possible. This is because the total length would have to be determined then divided by the number of columns, but that wouldn't account for words that need to be wrapped, and it would change each time the margins are adjusted, and so it would end up shifting and taking more lines than calculated, resulting in a shorter final line. The only way around this would be to always add a hyphen as the last character on a line then continue mid-word on the next line, which wouldn't be desirable. It could work for shorter strings that would only wrap once or maybe even a few times, but anything longer becomes far too unpredictable. The only way it might work would be to adjust the wrap function, or create a separate one, to allow a line to go past the ( STR_LEN / COLUMNS ) cutoff point until the next space, up to the point where it would actually run out of room, to prevent unintended roll-overs, but that seems unlikely to work as well, and it would require constant recalculating of number of lines, number of characters per line, and margins, so see how the change of any one variable affects the others, which would then have to be changed, which would affect the others, and end up being a vicious cycle.
REM
REM  Center text -- EXAMPLE -> call :centerwrap text
:centerwrap
setlocal EnableDelayedExpansion
SET CENTER=TRUE
goto wrap
REM  Center text and create a margin x spaces wide on the left side and y spaces on the right -- EXAMPLES -> call :centerjustify 5 20 text  OR  call :centerjustify 5 5 text  OR  call :centerjustify 0 10 text (can also use :centerindent, or make a label with whatever name is preferred)
:centerjustify
:centerindent
:centerindentwrap
:centerindentjustify
setlocal EnableDelayedExpansion
REM  Set the text to be wrapped (REMAINDER) and set the function name and first two parameters (x & y; as number and string) as variables for use in the paramater check & trim function (number variables are for checking if they're numbers and string variable is for displaying them if they're not, to help find the incorrectly worded call) and remove triple-quotes, if present, from first parameter (only if the variable is defined, since using SET to remove quotes from an empty variable causes issues), then call function and exit if check fails (first two parameters passed not valid numbers), otherwise call function to clean text to be wrapped (remove triple-quotes and swap out problematic characters with placeholders) and set center flag
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
REM  Set variables for parameter 2, which requires an additional line as not more than one expansion & substitution can be performed per line (no more variables can be set after it, so it must the last one done on each line)
SET /A PARAM2_NUMERICAL=%2 2> nul & SET PARAM2_TEXT=%2& IF DEFINED PARAM2_TEXT SET "PARAM2_TEXT=!PARAM2_TEXT:"""=!"
call :param_check_and_trim 2
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET CENTER=TRUE
REM  Use variable full of spaces set in param_check_and_trim function to create indent variable combining only the first x characters (spaces) as defined in the call
SET "INDENT=!SPACES:~0,%1!"
REM  Decrease columns by indent amount for justify functionality, so lines will be wrapped x characters sooner, creating a margin that size on the right
SET /A COLUMNS="( %COLUMNS% - %2 )"
goto wrap
REM  Indent all but the first line x spaces -- EXAMPLE -> call :hangindent 15 text
:hangindent
:hangindentwrap
:hangwrap
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
call :param_check_and_trim 1
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "HANGINDENT=!SPACES:~0,%1!"
goto wrap
REM  Indent all but the first line x spaces and create a margin y spaces wide on right side -- EXAMPLE -> call :hangjustify 15 5 text
:hangjustify
:hangjustifywrap
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
SET /A PARAM2_NUMERICAL=%2 2> nul & SET PARAM2_TEXT=%2& IF DEFINED PARAM2_TEXT SET "PARAM2_TEXT=!PARAM2_TEXT:"""=!"
call :param_check_and_trim 2
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "HANGINDENT=!SPACES:~0,%1!"
SET /A COLUMNS="( %COLUMNS% - %2 )"
goto wrap
REM  Indent all lines x spaces and create a margin x spaces wide on right side (note this always performs indentation as well, since it's unlikely it would be used on its own, though that can be done with indentjustify function below) -- EXAMPLE -> call :justify 5 text
:justify
:justifywrap
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
call :param_check_and_trim 1
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "INDENT=!SPACES:~0,%1!"
SET /A COLUMNS="( %COLUMNS% - %1 )"
goto wrap
REM  Indent all lines x spaces and create a margin y spaces wide on right side -- EXAMPLE -> call :indentjustify 5 15 text
:indentjustify
:indentjustifywrap
:doublewrap
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
SET /A PARAM2_NUMERICAL=%2 2> nul & SET PARAM2_TEXT=%2& IF DEFINED PARAM2_TEXT SET "PARAM2_TEXT=!PARAM2_TEXT:"""=!"
call :param_check_and_trim 2
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "INDENT=!SPACES:~0,%1!"
SET /A COLUMNS="( %COLUMNS% - %2 )"
goto wrap
REM  Indent all lines x spaces -- EXAMPLE -> call :indent 5 text
:indent
:indentwrap
:wrapindent
setlocal EnableDelayedExpansion
SET REMAINDER=%*& SET FUNCTION_NAME=%0& SET /A PARAM1_NUMERICAL=%1 2> nul & SET PARAM1_TEXT=%1& IF DEFINED PARAM1_TEXT SET "PARAM1_TEXT=!PARAM1_TEXT:"""=!"
call :param_check_and_trim 1
If "!PARAM_CHECK!" == "FAIL" endlocal & exit /b
call :wrap_input_clean
SET "INDENT=!SPACES:~0,%1!"
REM  Base word-wrap functionality; call directly if none of the above functions are desired (consists of wrap, outloop, and line_wrap functions; param_check_and_trim and char_count used for above functions) -- EXAMPLE -> call :wrap text
:wrap
setlocal EnableDelayedExpansion
REM  Exit function if no text was entered. If desired, this could be set to notify or perform an echo. (blank line) as well.
If [%1] == [] endlocal & exit /b
REM  Set input and call input clean function if wrap function is called directly, as these wouldn't be done above, and shouldn't be done again if already done above. Placed on the same line to avoid the parentheses required for a multi-line statement, which would break the function if any non-escaped closing parentheses are in the text passed to the function
If NOT "!INDENTED!" == "TRUE" SET REMAINDER=%*& call :wrap_input_clean
REM  Check if first parameter (first character) is a dot, in which case remove it
SET "DOTCHECK=!REMAINDER:~0,1!"
If "!DOTCHECK!" == "." SET "REMAINDER=!REMAINDER:~1!"
SET REMAINDER=!INDENT!!REMAINDER!
:outloop
SET /A LASTSP=%COLUMNS% - 1
CALL :line_wrap
REM  Remove any carets from output (unclear why, but whenever a caret is used in the input, it's doubled in the output)
SET "LINE=!LINE:^=!" 
REM  Send line to center function if center flag is set to true, otherwie echo it normally. This is processed each time the line_wrap function determines an EOL (end-of-line) and sends the currently processed line, which cuts off at the last space before a word that would be split, to the outloop function for display.
If "!CENTER!" == "TRUE" (
  REM  Insert ASCII character at beginning of line to preserve leading spaces (indent), which would otherwise not be counted as part of argument in center function
  SET LINE=!LINE!
  call :center !LINE!
) Else (
  REM  Change ASCII placeholders assigned earlier back to " and & before output is displayed
  SET "LINE=!LINE:="!"
  SET "LINE=!LINE:=&!"
  echo !LINE!
)
IF DEFINED REMAINDER goto outloop
endlocal
exit /b
:line_wrap
SET /A LASTSP-=1
CALL SET LINE=%%REMAINDER:~%LASTSP%,1%%
IF NOT DEFINED LINE endlocal & SET "LINE=%REMAINDER%" & SET "REMAINDER=" & exit /b
IF NOT "%LINE%"==" " goto line_wrap
CALL SET LINE=%%REMAINDER:~0,%LASTSP%%%
SET /A LASTSP+=1
REM  !INDENT! adds indentation, if present, in front of each line
CALL SET REMAINDER=!INDENT!!HANGINDENT!%%REMAINDER:~%LASTSP%%%
endlocal
exit /b
REM  Checks first (x = indent) and, if applicable, second (y = justify/margin) parameter(s) to ensure they're valid (positive numbers). If not, displays error message to alert programmer of the error, otherwise removes them from input string and sets INDENTED=TRUE. FOR loop to cycle through parameters and keep only 3+ (i.e. FOR /F "tokens=3*" %%a IN ("!REMAINDER!") DO SET REMAINDER=%%a %%b) can NOT be used as it will ignore multiple spaces (e.g. "text   to   be   displayed" would become "text to be displayed"). The count loop could be replaced by a call to the length function, but since it's only two additional lines there's no need and this keeps it all together. Because this removes the x and y parameters and leaves the rest of the string intact, functions that call it do not need to use a dot (.) to keep leading spaces; however, doing so will not affect anything.
:param_check_and_trim
setlocal EnableDelayedExpansion
SET "ASTERISKS=********************************************************************************************************************************************************************************************************"
SET "ASTERISKS=!ASTERISKS:~0,%COLUMNS%!"
SET "ASTERISKS=!ASTERISKS:~10!"
If %1 equ 1 (
  If !PARAM1_NUMERICAL! lss 1 (
    call :center """!ASTERISKS!"""& call :centerwrap """Invalid input -- !FUNCTION_NAME! function requires a positive number as the first parameter (e.g. "call !FUNCTION_NAME! 5 text"). This is a problem with the script code, NOT with user input. The following parameter was used (note that if more than one word, a variable was passed to the function and the variable's contents are what's shown here):"""& echo. & call :centerwrap """PARAMETER 1: '!PARAM1_TEXT!'"""& call :center """!ASTERISKS!"""& endlocal & SET "PARAM_CHECK=FAIL" & exit /b
  ) Else (
    FOR /F "tokens=1" %%a IN ("!REMAINDER!") DO SET CHARS=%%a& SET /A i=1
  )
)
If %1 equ 2 (
  If !PARAM1_NUMERICAL! lss 1 (
    If !PARAM2_NUMERICAL! lss 1 (
      call :center """!ASTERISKS!"""& call :centerwrap """Invalid input -- !FUNCTION_NAME! function requires a positive number for both the first and second parameters (e.g. "call !FUNCTION_NAME! 15 5 text"), but both are invalid. This is a problem with the script code, NOT with user input. The following was used (note that if more than one word, a variable was passed to the function and the variable's contents are what's shown here):"""& echo. & call :centerwrap """PARAMETER 1: '!PARAM1_TEXT!'"""& echo. & call :centerwrap """PARAMETER 2: '!PARAM2_TEXT!'"""& call :center """!ASTERISKS!"""& endlocal & SET "PARAM_CHECK=FAIL" & exit /b
    ) Else (
      call :center """!ASTERISKS!"""& call :centerwrap """Invalid input -- !FUNCTION_NAME! function requires a positive number for both the first and second parameters (e.g. "call !FUNCTION_NAME! 15 5 text"), but the first parameter is invalid. This is a problem with the script code, NOT with user input. The following was used (note that if more than one word, a variable was passed to the function and the variable's contents are what's shown here):"""& echo. & call :centerwrap """PARAMETER 1: '!PARAM1_TEXT!'"""& call :center """!ASTERISKS!"""& endlocal & SET "PARAM_CHECK=FAIL" & exit /b
    )
  ) Else (
    If !PARAM2_NUMERICAL! lss 1 (
      call :center """!ASTERISKS!"""& call :centerwrap """Invalid input -- !FUNCTION_NAME! function requires a positive number for both the first and second parameters (e.g. "call !FUNCTION_NAME! 15 5 text"), but the second parameter is invalid. This is a problem with the script code, NOT with user input. The following was used (note that if more than one word, a variable was passed to the function and the variable's contents are what's shown here):"""& echo. & call :centerwrap """PARAMETER 2: '!PARAM2_TEXT!'"""& call :center """!ASTERISKS!"""& endlocal & SET "PARAM_CHECK=FAIL" & exit /b
    ) Else (
      FOR /F "tokens=1,2" %%a IN ("!REMAINDER!") DO SET CHARS=%%a%%b& SET /A i=2
    )
  )
)
:char_count_loop
FOR %%a IN (!CHARS!) DO SET "CHARS=!CHARS:~1!" & SET /A i+=1
If !CHARS! neq 0 goto char_count_loop
endlocal & SET "REMAINDER=!REMAINDER:~%i%!" & SET "INDENTED=TRUE" & SET "SPACES=                                                                                                                                                                                                                                 "
exit /b
:wrap_input_clean
setlocal EnableDelayedExpansion
REM  Remove triple-quotes since they are not wanted in final output. Triple-quotes could be changed to (almost) anything desired, such as "- or ". (double-quotes ("") won't work, however). Then change ampersands (&) and remaining quotes in input to ASCII characters (Alt+004 and Alt+005, respectively) since ampersands are problematic and quotes sometimes break "IF NOT "%LINE%"==" " goto line_wrap" line in Line_wrap function, since it reads as "IF NOT """==" " goto line_wrap" -- Note that this should be possible for other characters as well, such as carets (^).
SET "REMAINDER=!REMAINDER:"""=!"
SET "REMAINDER=%REMAINDER:"=%"
SET "REMAINDER=!REMAINDER:&=!"
endlocal & SET "REMAINDER=%REMAINDER%"
exit /b