在批处理中,我将如何从变量中删除所有非字母数字(a-z,A-Z,0-9,_)字符?
我很确定我需要使用 findstr 和正则表达式。
MC ND 的解决方案有效,但速度真的很慢(小测试样本需要 ~1 秒)。
这是由echo "!_buf!"|findstr ...
构造引起的,因为对于每个字符,管道都会创建两个cmd实例.exe并开始findstr
。
但这也可以用纯批次来解决。
测试每个字符是否在map
变量中
:test
set "_input=Th""is&& is not good _maybe_???"
set "_output="
set "map=abcdefghijklmnopqrstuvwxyz 1234567890"
:loop
if not defined _input goto endLoop
for /F "delims=*~ eol=*" %%C in ("!_input:~0,1!") do (
if "!map:%%C=!" NEQ "!map!" set "_output=!_output!%%C"
)
set "_input=!_input:~1!"
goto loop
:endLoop
echo(!_output!
当goto
回路被移除时,它可能会加快速度。
然后,您需要首先计算字符串长度,然后对每个字符进行迭代,然后使用FOR/L循环。
该解决方案比上述方法快~6倍,比MC ND解决方案快~40倍
set "_input=Th""is&& is not good _maybe_!~*???"
set "_output="
set "map=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ 1234567890"
%$strLen% len _input
for /L %%n in (0 1 %len%) DO (
for /F "delims=*~ eol=*" %%C in ("!_input:~%%n,1!") do (
if "!map:%%C=!" NEQ "!map!" set "_output=!_output!%%C"
)
)
exit /b
宏$strlen可以定义
为set LF=^
::Above 2 blank lines are required - do not remove
@set ^"n=^^^%LF%%LF%^%LF%%LF%^^":::: StrLen pResult pString
set $strLen=for /L %%n in (1 1 2) do if %%n==2 (%n%
for /F "tokens=1,2 delims=, " %%1 in ("!argv!") do (%n%
set "str=A!%%~2!"%n%
set "len=0"%n%
for /l %%A in (12,-1,0) do (%n%
set /a "len|=1<<%%A"%n%
for %%B in (!len!) do if "!str:~%%B,1!"=="" set /a "len&=~1<<%%A"%n%
)%n%
for %%v in (!len!) do endlocal^&if "%%~b" neq "" (set "%%~1=%%v") else echo %%v%n%
) %n%
) ELSE setlocal enableDelayedExpansion ^& set argv=,
编辑 - @jeb是对的。这有效,但实际上非常非常慢。
@echo off
setlocal enableextensions enabledelayedexpansion
set "_input=Th""is&& is not good _maybe_???"
set "_output="
:loop
if not defined _input goto endLoop
set "_buf=!_input:~0,1!"
set "_input=!_input:~1!"
echo "!_buf!"|findstr /i /r /c:"[a-z 0-9_]" > nul && set "_output=!_output!!_buf!"
goto loop
:endLoop
echo !_output!
endlocal
所以,回到绘图板。如何让它更快?让我们尝试尽可能少地执行操作,并使用尽可能多的长子字符串。所以,分两步完成
1.- 删除所有可能产生问题的不良字符。为此,我们将使用 for 命令的可恨性将这些字符标识为分隔符,然后连接字符串的其余部分 god 字符
2.- 删除其余的坏字符,使用有效字符作为分隔符将它们定位在字符串中以查找坏字符的子字符串,然后在字符串中替换
所以,我们以(sintax适应这里已经回答的内容)结束
@echo off
setlocal enableextensions enabledelayedexpansion
rem Test empty string
call :doClean "" output
echo "%output%"
rem Test mixed strings
call :doClean "~~asd123#()%%%^"^!^"~~~^"""":^!!!!=asd^>^<bm_1" output
echo %output%
call :doClean "This&& is ;;;;not ^^good _maybe_!~*???" output
echo %output%
rem Test clean string
call :doClean "This is already clean" output
echo %output%
rem Test all bad string
call :doClean "*******//////\\\()()()()" output
echo "%output%"
rem Test long string
set "zz=This&& is not ^^good _maybe_!~*??? "
set "zz=TEST: %zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%%zz%"
call :doClean "%zz% TEST" output
echo %output%
rem Time long string
echo %time%
for /l %%# in (1 1 100) do call :doClean "%zz%" output
echo %time%
exit /b
rem ---------------------------------------------------------------------------
:doClean input output
setlocal enableextensions enabledelayedexpansion
set "map=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890 "
set "input=%~1"
set "output="
rem Step 1 - Remove critical delimiters
(
:purgeCritical
for /L %%z in (1 1 10) do (
for /f tokens^=1^-9^,^*^ delims^=^=^"^"^~^;^,^&^*^%%^:^!^(^)^<^>^^ %%a in ("!input!") do (
set "output=!output!%%a%%b%%c%%d%%e%%f%%g%%h%%i"
set "input=%%j"
)
if not defined input goto outPurgeCritical
)
goto purgeCritical
)
:outPurgeCritical
rem Step 2 - remove any remaining special character
(
:purgeNormal
for /L %%z in (1 1 10) do (
set "pending="
for /f "tokens=1,* delims=%map%" %%a in ("!output!") do (
set "output=!output:%%a=!"
set "pending=%%b"
)
if not defined pending goto outPurgeNormal
)
goto purgeNormal
)
:outPurgeNormal
endlocal & set "%~2=%output%"
goto :EOF
也许不是最快的,但至少是一个"体面"的解决方案
@echo eof
call :purge "~~asd123#()%%%^"^!^"~~~^:^=asd^>^<bm_1" var
echo (%var%)
goto :eof
:purge StrVar [RtnVar]
setlocal disableDelayedExpansion
set "str1=%~1"
setlocal enableDelayedExpansion
for %%a in ( - ! @ # $ % ^^ ^& + / ^< ^> . ' [ ] { } ` ^| ^" ) do (
set "str1=!str1:%%a=!"
)
rem dealing with some delimiters
set "str1=!str1:(=!"
set "str1=!str1:)=!"
set "str1=!str1:;=!"
set "str1=!str1:,=!"
set "str1=!str1:^^=!"
set "str1=!str1:^~=!"
set "temp_str="
for %%e in (%str1%) do (
set "temp_str=!temp_str!%%e"
)
endlocal & set "str1=%temp_str%"
setlocal disableDelayedExpansion
set "str1=%str1:!=%"
set "str1=%str1::=%"
set "str1=%str1:^^~=%"
for /f "tokens=* delims=~" %%w in ("%str1%") do set "str1=%%w"
endlocal & set "str1=%str1%"
endlocal & if "%~2" neq "" (set %~2=%str1%) else echo %str1%
goto :eof
仍然无法处理~ and =
但正在努力
编辑:现在=
将被清除编辑: ~
现在将被清除