使用Windows批处理从文件中删除尾随空格?
本Hocking引用的DosTips RTRIM函数可用于创建一个脚本,该脚本可以正确修剪文本文件中的每一行。但是,功能相对较慢。
DosTips用户(和版主)aGerman开发了一个very efficient right trim algorithm。他将该算法作为批量“宏”实现 - 这是一个将复杂迷你脚本存储在可从内存执行的环境变量中的有趣概念。带有参数的宏是一个重要的讨论话题,它本身并不与这个问题相关。
我已经提取了一个德国人的算法,并把它放在下面的批处理脚本中。该脚本需要将文本文件的名称作为唯一参数,然后右键修剪文件中每行的空格。
@echo off
setlocal enableDelayedExpansion
set "spcs= "
for /l %%n in (1 1 12) do set "spcs=!spcs!!spcs!"
findstr /n "^" "%~1" >"%~1.tmp"
setlocal disableDelayedExpansion
(
for /f "usebackq delims=" %%L in ("%~1.tmp") do (
set "ln=%%L"
setlocal enableDelayedExpansion
set "ln=!ln:*:=!"
set /a "n=4096"
for /l %%i in (1 1 13) do (
if defined ln for %%n in (!n!) do (
if "!ln:~-%%n!"=="!spcs:~-%%n!" set "ln=!ln:~0,-%%n!"
set /a "n/=2"
)
)
echo(!ln!
endlocal
)
) >"%~1"
del "%~1.tmp" 2>nul
假设脚本称为rtrimFile.bat,那么它可以通过命令行调用如下:
rtrimFile "fileName.txt"
关于性能的音符
原始DosTips RTRIM函数执行线性搜索并默认修剪最多32个空格。它必须在每个空间迭代一次。
aGerman算法使用二分搜索,它能够在13次迭代中修整批次允许的最大字符串大小(最多〜8k空间)。
不幸的是,当处理文本时批处理非常慢。即使使用高效的rtrim功能,在我的机器上修剪1MB文件也需要大约70秒的时间。问题是,只需读写文件而不做任何修改就需要花费大量时间。此答案使用FOR循环读取文件,并使用FINDSTR在每行的前面添加行号,以便保留空行。它切换延迟扩展以防止!
被破坏,并使用搜索和替换操作从每行删除行号前缀。所有那些甚至开始做rtrim之前。
使用alternate file read mechanism that uses set /p
可以使性能几乎翻倍。但是,set/p方法限制为每行大约1k字节,并且会剥去每行的尾随控制字符。
如果您需要定期修剪大文件,那么即使性能提高一倍也可能不足。有时间下载(如果可能)任何一个可以在瞬间处理文件的工具。
如果您不能使用非本机软件,那么您可以尝试通过CSCRIPT批处理命令执行VBScript或JScript。任何一个会更快。
更新 - 与JREPL.BAT
JREPL.BAT快速的解决方案是一个正则表达式查找/替换工具,可以非常有效地解决这个问题。它是纯粹的脚本(混合批处理/ JScript),可以从XP以后的任何Windows机器上本机运行。没有第三方exe文件是必要的。
随着JREPL.BAT您的PATH中的某个地方,你可以去除尾随文件“的test.txt”空间这个简单的命令:
jrepl " +$" "" /f test.txt /o -
如果你把一个批处理脚本中的命令,则必须与CALL之前的命令:
call jrepl " +$" "" /f test.txt /o -
谢谢,我会尽快尝试这个,一旦我再次达到它。 – HeinrichStack 2012-02-17 06:41:19
谢谢,它工作。我希望我能详细了解这个脚本,而不必成为批处理专家:) – HeinrichStack 2012-02-21 07:03:20
PS只是对性能的一个小反馈,它正在以小于1 MB /秒的速率修剪大文本文件双核英特尔2.66 GHz,xp sp3,2GB内存。我知道上述意思几乎没有,但只是fyi。对我来说,如果我修剪一个10MB的文件,这意味着超过10分钟...所以,问题是:你能想象上述批处理的一些限制,以及一些提高性能的可能性吗?行集/ a“k = 4096”%\ n%设置了一些缓冲区或者它有什么好处? – HeinrichStack 2012-02-21 07:52:34
该做什么提示有implementation of RTrim,对于批处理文件的工作原理:
:rTrim string char max -- strips white spaces (or other characters) from the end of a string
:: -- string [in,out] - string variable to be trimmed
:: -- char [in,opt] - character to be trimmed, default is space
:: -- max [in,opt] - maximum number of characters to be trimmed from the end, default is 32
:$created 20060101 :$changed 20080219 :$categories StringManipulation
:$source http://www.dostips.com
SETLOCAL ENABLEDELAYEDEXPANSION
call set string=%%%~1%%
set char=%~2
set max=%~3
if "%char%"=="" set char= &rem one space
if "%max%"=="" set max=32
for /l %%a in (1,1,%max%) do if "!string:~-1!"=="%char%" set string=!string:~0,-1!
(ENDLOCAL & REM RETURN VALUES
IF "%~1" NEQ "" SET %~1=%string%
)
EXIT /b
如果你不习惯在批处理文件中使用的功能,read this 。
谢谢,但我需要从命令行调用它。任何建议如何? – HeinrichStack 2012-02-16 12:54:30
@ HeinrichStack:创建一个批处理文件,用它的参数调用这个函数... – 2012-02-16 20:49:51
我用这个Python的脚本2打印尾随空白的线条和手动删除它们:
#!/usr/bin/env python2
import sys
if not sys.argv[1:]:
sys.exit('usage: whitespace.py <filename>')
for no, line in enumerate(open(sys.argv[1], 'rb').read().splitlines()):
if line.endswith(' '):
print no+1, line
我知道,Python是没有预装的Windows,但至少它跨平台工作。
我只是找到了修剪过的空格字符串的一个非常好的解决方案:
你曾经被称为子程序使用call
和扩大使用%*
所有参数?您会注意到任何前导和/或尾随空白都被删除。任何其他角色之间出现的空白都会被保留;所有其他命令令牌分隔符,
,;
,=
以及非破坏空间(字符代码0xFF
)也是如此。这种效果,我要利用我的脚本:
@echo off
set "STR="
set /P STR="Enter string: "
rem /* Enable Delayed Expansion to avoid trouble with
rem special characters: `&`, `<`, `>`, `|`, `^` */
setlocal EnableDelayedExpansion
echo You entered: `!STR!`
call :TRIM !STR!
echo And trimmed: `!RES!`
endlocal
exit /B
:TRIM
set "RES=%*"
exit /B
这个脚本预计到,然后修整用户输入的字符串。这当然也可以应用于文件的行(原始问题是关于,但使用for /F
一行一行地读取,在其他答案中总是显示,所以我在此跳过)。要仅修剪一侧的字符串,请在修剪之前在对面添加单个字符,然后再将其移除。
这种方法已经得到了一定的局限性,虽然:它不处理字符%
,!
,^
和"
正常。为了克服这个问题,几个中间字符串操作成为必需的:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "STR="
set /P STR="Enter string: "
setlocal EnableDelayedExpansion
echo You entered: `!STR!`
set "STR=!STR:%%=%%%%!"
set "STR=!STR:"=""!^"
if not "%STR%"=="%STR:!=%" set "STR=!STR:^=^^^^!"
set "STR=%STR:!=^^^!%"
call :TRIM !STR!
set "RES=!RES:""="!^"
echo And trimmed: `!RES!`
endlocal
endlocal
exit /B
:TRIM
set "RES=%*"
exit /B
更新:我只是意识到人物&
,<
,>
和|
仍然会造成麻烦。一旦我找到解决方案,我将回到这里并相应地修复代码。
根据用户Aacini的this answer删除尾随空格是一个不错的技巧;我对其进行了修改,以便保留字符串中出现的所有其他空格。因此,这里是代码:
@echo off
setlocal EnableDelayedExpansion
rem // This is the input string:
set "x= This is a text string containing many spaces. "
rem // Ensure there is at least one trailing space; then initialise auxiliary variables:
set "y=%x% " & set "wd=" & set "sp="
rem // Now here is the algorithm:
set "y=%y: =" & (if defined wd (set "y=!y!!sp!!wd!" & set "sp= ") else (set "sp=!sp! ")) & set "wd=%"
rem // Return messages:
echo input: "%x%"
echo output: "%y%"
endlocal
然而,当设定^
,!
的人物,出现在字符串中"
这种方法失败。
我忘了提及,我想从命令行中这样做。可能没有任何额外的软件 – HeinrichStack 2012-02-16 13:04:54
我忘了提及。我想用机器语言来做到这一点。最好不使用汇编程序或编译器:-) _使用你可以使用的工具,这就是它们的用途。否则,你正在浪费时间重新发明轮子(并且可能使它们变得平坦)。 – paxdiablo 2012-02-18 15:11:17