2011-12-21 131 views
2

這個問題已經在stackoverflow上問了很多,但我似乎無法使它工作。任何提示讚賞。下面是需要被刪除的文本文件(擴展名爲.mpl)含有違規內容:bat文件替換文本文件中的字符串

plotsetup('ps', 'plotoutput = "plotfile.eps"', 'plotoptions' = "color=rgb,landscape,noborder"); 
print(PLOT3D(MESH(Array(1..60, 1..60, 1..3, [[[.85840734641021,0.,-0.], 
[HFloat(undefined),HFloat(undefined),HFloat(undefined)],[.857971665313419,.0917163905694189,-.16720239349226], 
... more like that ... 
[.858407346410207,-3.25992468340355e-015,5.96532373555817e-015]]], datatype = float[8], order = C_order)),SHADING(ZHUE),STYLE(PATCHNOGRID),TRANSPARENCY(.3),LIGHTMODEL(LIGHT_4),ORIENTATION(35.,135.),SCALING(CONSTRAINED),AXESSTYLE(NORMAL))); 

我想刪除的每個實例:

[HFloat(undefined),HFloat(undefined),HFloat(undefined)], 

,並有成千上萬這樣的情況下!注意:方括號和逗號將被刪除。沒有空間,所以我有頁面和頁面:

[HFloat(undefined),HFloat(undefined),HFloat(undefined)], 
[HFloat(undefined),HFloat(undefined),HFloat(undefined)], 
[HFloat(undefined),HFloat(undefined),HFloat(undefined)], 

我不會在這裏列出所有失敗的嘗試。下面是我來最接近:

@echo off 

SetLocal 
cd /d %~dp0 

if exist testCleaned.mpl del testCleaned.mpl 

SetLocal EnableDelayedExpansion 

Set OldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)], 
Set NewString= 

pause 

FOR /F "tokens=* delims= " %%I IN (test.mpl) DO (
    set str=%%I 
    set str=!str:OldString=NewString! 
    echo !str! >> testCleaned.mpl 
    endlocal 
) 

EndLocal 

上述被串在一起,因爲它是,從代碼片段在網上找到,尤其是在計算器,例如Problem with search and replace batch file

它能做什麼是產生一個截斷的文件,內容如下:

plotsetup('ps', 'plotoutput = "plotfile.eps"', 'plotoptions' = "color=rgb,landscape,noborder"); 
!str! 

請不要猶豫,要求澄清。道歉,如果你覺得這個問題已經得到解答。我非常感謝你是否會爲我複製粘貼相關代碼,因爲我已經嘗試了幾個小時。

獎勵:這個自動命名可以工作嗎? 「%%~nICleaned.mpl

+0

您是否嘗試過其他工具而不是DOS腳本? – kev 2011-12-21 11:35:32

+0

我建議使用C#腳本:http://www.csscript.net/ – Hybrid 2011-12-21 11:55:31

+0

kev,不,我沒有嘗試過其他腳本。我需要修改的文件的內容是用Maple(Maplesoft)創建的混亂的postscript文件,我試圖用Maple的StringTools修復它,但它適用於小文件,但它不適用於大文件(對於某些原因)。經過幾個小時的調試失敗後,我認爲我會用谷歌的東西,和DOS腳本是最常見的命中之一。如果不涉及數小時的新軟件安裝,我很樂意嘗試其他方法。如果有幫助,我在Ubuntu上有一個完全可用的python系統。謝謝! – PatrickT 2011-12-21 14:54:45

回答

6

最大的問題與您現有的代碼,該代碼是SetLocal enableDelayedExpansion是missplaced - set str=%%I後,它應該是在循環中。

其他問題:

  • 將剝離開頭線;
  • 將去除前導空格從每行
  • 將剝離空白(空)線
  • 將打印ECHO is off如果任何線變爲空或包含取代後僅空格
  • 將在每一行的末尾添加額外的空間(沒有注意到這一點,直到我看到jeb的回答)

優化問題 - 使用>>可以相對較慢。將整個循環封裝在()中會更快,然後使用>

以下是關於使用Windows批處理可以做到的最好方法。我自動根據請求命名輸出,做得更好 - 它會自動保留原始名稱的擴展名。

@echo off 
SetLocal 
cd /d %~dp0 
Set "OldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)]," 
Set "NewString=" 
set file="test.mpl" 
for %%F in (%file%) do set outFile="%%~nFCleaned%%~xF" 
pause 
(
    for /f "skip=2 delims=" %%a in ('find /n /v "" %file%') do (
    set "ln=%%a" 
    setlocal enableDelayedExpansion 
    set "ln=!ln:*]=!" 
    if defined ln set "ln=!ln:%OldString%=%NewString%!" 
    echo(!ln! 
    endlocal 
) 
)>%outFile% 

已知限制

  • 限制爲略低於每行8K之前和替換之後
  • 搜索字符串不能包括=!,也無法使用*~
  • 啓動替換字符串不能包含!
  • 搜索部分搜索結果小時,取而代之的是不區分大小寫
  • 最後一行將始終與換行符<CR><LF>結束,即使原來沒有

除了第一個限制可能被淘汰,但它需要大量的代碼,並且將是極其可怕慢。解決方案將需要通過每行字符搜索的字符。最後一個限制需要進行一些尷尬的測試,以確定最後一行是否換行,如果不換行,則最後一行必須使用<nul SET /P "ln=!ln!"技巧打印。

有趣的功能(或限制,取決於視角)

  • 結束與<LF>線的Unix風格的文件都將轉換到Windows風格與<CR><LF>

結束行有使用批處理其他解決方案這要快得多,但它們都有更多的限制。

更新 - 我發佈了一個新的純批量解決方案,可以執行區分大小寫的搜索,並且對搜索或替換字符串內容沒有限制。它對行長,尾隨控制字符和行格式有更多的限制。性能並不差,特別是如果替換次數較少。http://www.dostips.com/forum/viewtopic.php?f=3&t=2710

附錄基於下面的評論

,一批溶液不會爲因爲線長度限制的這個特殊問題的工作。

但是,只要您願意忍受批處理的侷限性和相對較差的性能,此代碼是基於批處理的搜索和替換實用程序的良好基礎。

有很多更好的文本處理工具可用,但它們不符合Windows標準。我最喜歡的套裝是GNU Utilities for Win32套裝。這些實用程序是免費的,不需要任何安裝。

下面是使用GNU工具

@echo off 
setlocal 
cd /d %~dp0 
Set "OldString=\[HFloat(undefined),HFloat(undefined),HFloat(undefined)\]," 
Set "NewString=" 
set file="test.mpl" 
for %%F in (%file%) do set outFile="%%~nFCleaned%%~xF" 
pause 
sed -e"s/%OldString%/%NewString%/g" <%file% >%outfile% 


更新爲Windows sed的解決方案2013年2月19日

sed的,如果你在有規則禁止的站點執行任務可能不是一個選項安裝從網絡上下載的可執行文件。

JScript具有良好的正則表達式處理,並且在所有現代Windows平臺(包括XP)上都是標準的。在Windows平臺上執行搜索和替換操作是一個很好的選擇。

我寫了一個很容易從批處理腳本調用的混合JScript/Batch搜索和替換腳本(REPL.BAT)。少量的代碼提供了許多強大的功能;沒有sed那麼強大,但足以應付這一任務以及其他許多問題。它也非常快,比任何純批處理解決方案都快得多。它也沒有任何固有的線路長度限制。

這是一個使用我的REPL.BAT實用程序完成任務的批處理腳本。

@echo off 
setlocal 
cd /d %~dp0 
Set "OldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)]," 
Set "NewString=" 
set file="test.txt" 
for %%F in (%file%) do set outFile="%%~nFCleaned%%~xF" 
pause 
call repl OldString NewString le <%file% >%outfile% 

我使用L選項來指定文字搜索字符串,而不是一個正則表達式,並E選項,通過搜索和名稱替換通過環境變量的字符串,而不是使用命令行字符串文字。

這是上述代碼調用的REPL.BAT實用程序腳本。完整的文檔包含在腳本中。

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment 

::************ Documentation *********** 
::: 
:::REPL Search Replace [Options [SourceVar]] 
:::REPL /? 
::: 
::: Performs a global search and replace operation on each line of input from 
::: stdin and prints the result to stdout. 
::: 
::: Each parameter may be optionally enclosed by double quotes. The double 
::: quotes are not considered part of the argument. The quotes are required 
::: if the parameter contains a batch token delimiter like space, tab, comma, 
::: semicolon. The quotes should also be used if the argument contains a 
::: batch special character like &, |, etc. so that the special character 
::: does not need to be escaped with ^. 
::: 
::: If called with a single argument of /? then prints help documentation 
::: to stdout. 
::: 
::: Search - By default this is a case sensitive JScript (ECMA) regular 
:::   expression expressed as a string. 
::: 
:::   JScript syntax documentation is available at 
:::   http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx 
::: 
::: Replace - By default this is the string to be used as a replacement for 
:::   each found search expression. Full support is provided for 
:::   substituion patterns available to the JScript replace method. 
:::   A $ literal can be escaped as $$. An empty replacement string 
:::   must be represented as "". 
::: 
:::   Replace substitution pattern syntax is documented at 
:::   http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx 
::: 
::: Options - An optional string of characters used to alter the behavior 
:::   of REPL. The option characters are case insensitive, and may 
:::   appear in any order. 
::: 
:::   I - Makes the search case-insensitive. 
::: 
:::   L - The Search is treated as a string literal instead of a 
:::    regular expression. Also, all $ found in Replace are 
:::    treated as $ literals. 
::: 
:::   E - Search and Replace represent the name of environment 
:::    variables that contain the respective values. An undefined 
:::    variable is treated as an empty string. 
::: 
:::   M - Multi-line mode. The entire contents of stdin is read and 
:::    processed in one pass instead of line by line.^anchors 
:::    the beginning of a line and $ anchors the end of a line. 
::: 
:::   X - Enables extended substitution pattern syntax with support 
:::    for the following escape sequences: 
::: 
:::    \\  - Backslash 
:::    \b  - Backspace 
:::    \f  - Formfeed 
:::    \n  - Newline 
:::    \r  - Carriage Return 
:::    \t  - Horizontal Tab 
:::    \v  - Vertical Tab 
:::    \xnn - Ascii (Latin 1) character expressed as 2 hex digits 
:::    \unnnn - Unicode character expressed as 4 hex digits 
::: 
:::    Escape sequences are supported even when the L option is used. 
::: 
:::   S - The source is read from an environment variable instead of 
:::    from stdin. The name of the source environment variable is 
:::    specified in the next argument after the option string. 
::: 

::************ Batch portion *********** 
@echo off 
if .%2 equ . (
    if "%~1" equ "/?" (
    findstr "^:::" "%~f0" | cscript //E:JScript //nologo "%~f0" "^:::" "" 
    exit /b 0 
) else (
    call :err "Insufficient arguments" 
    exit /b 1 
) 
) 
echo(%~3|findstr /i "[^SMILEX]" >nul && (
    call :err "Invalid option(s)" 
    exit /b 1 
) 
cscript //E:JScript //nologo "%~f0" %* 
exit /b 0 

:err 
>&2 echo ERROR: %~1. Use REPL /? to get help. 
exit /b 

************* JScript portion **********/ 
var env=WScript.CreateObject("WScript.Shell").Environment("Process"); 
var args=WScript.Arguments; 
var search=args.Item(0); 
var replace=args.Item(1); 
var options="g"; 
if (args.length>2) { 
    options+=args.Item(2).toLowerCase(); 
} 
var multi=(options.indexOf("m")>=0); 
var srcVar=(options.indexOf("s")>=0); 
if (srcVar) { 
    options=options.replace(/s/g,""); 
} 
if (options.indexOf("e")>=0) { 
    options=options.replace(/e/g,""); 
    search=env(search); 
    replace=env(replace); 
} 
if (options.indexOf("l")>=0) { 
    options=options.replace(/l/g,""); 
    search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1"); 
    replace=replace.replace(/\$/g,"$$$$"); 
} 
if (options.indexOf("x")>=0) { 
    options=options.replace(/x/g,""); 
    replace=replace.replace(/\\\\/g,"\\B"); 
    replace=replace.replace(/\\b/g,"\b"); 
    replace=replace.replace(/\\f/g,"\f"); 
    replace=replace.replace(/\\n/g,"\n"); 
    replace=replace.replace(/\\r/g,"\r"); 
    replace=replace.replace(/\\t/g,"\t"); 
    replace=replace.replace(/\\v/g,"\v"); 
    replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g, 
    function($0,$1,$2){ 
     return String.fromCharCode(parseInt("0x"+$0.substring(2))); 
    } 
); 
    replace=replace.replace(/\\B/g,"\\"); 
} 
var search=new RegExp(search,options); 

if (srcVar) { 
    WScript.Stdout.Write(env(args.Item(3)).replace(search,replace)); 
} else { 
    while (!WScript.StdIn.AtEndOfStream) { 
    if (multi) { 
     WScript.Stdout.Write(WScript.StdIn.ReadAll().replace(search,replace)); 
    } else { 
     WScript.Stdout.WriteLine(WScript.StdIn.ReadLine().replace(search,replace)); 
    } 
    } 
} 
+0

dbenham,非常感謝!我特別感謝你的詳細解釋。毫無疑問,這對其他人也是有用的。 所以我測試了我的問題中發佈的示例文件上的解決方案,並且它工作正常。幸運的是,該文件不包含這些=! *〜 可悲的是,它不適用於我的真實文件。我認爲這個問題是一個問題。也許我的文件違反了8K限制或其他大小限制? 由於評論中的字符數有限制,所以讓我在下面的下一條評論中進行一點說明。 – PatrickT 2011-12-21 16:34:32

+0

我的現實生活中的文件就像我發佈的示例一樣,除了重量爲11,226,123字節。在openoffice中,我得到了(超過1700頁,仍在計數,將用最終計數更新),其中大部分填充了違規行[HFloat(未定義),HFloat(未定義),HFloat(未定義)], 多個實例之間沒有空間。 如果它不是完全難過的話,這將是搞笑的。 這是一個太大的問題嗎?任何方式救我? 非常感謝! – PatrickT 2011-12-21 16:43:58

+0

11,226,123字節 - > 1934頁在openoffice中。 – PatrickT 2011-12-21 16:53:12

0

我不是批處理文件的專家,所以我無法爲您的問題提供直接解決方案。

但是,要解決您的問題,使用替代批處理文件可能會更簡單。

例如,我建議使用http://www.csscript.net/(如果您知道C#)。這個工具將允許你運行批處理文件這樣的C#文件,但是可以讓你使用C#編寫腳本,而不是使用可怕的批處理文件語法:)

如果你知道python,另一種方法是使用python。

但我想問題是,在另一種編程語言中這種任務可能更容易。

+0

感謝混合。我無法評論bach文件的語法有多可怕,這取決於相關內容,我只需要涉及postscript代碼,你會稱之爲漂亮嗎? ;-) 所以我看了CS腳本鏈接,謝謝,這將是有用的。似乎更多一點,我該怎麼說呢,直覺呢? 你有Python代碼手頭會做字符串替換描述?我正在學python,所以對我來說這是一個很好的練習。 – PatrickT 2011-12-21 16:01:18

+0

我在Windows上的Linux和楓樹上的python - 它似乎有很多工作都在兩個操作系統上,所以既然破碎的文件是在Windows上生成我的第一反射是尋找一個Windows解決方案,但如果該批文件腳本拒絕在接下來的幾天內讓步,我會試着用python。謝謝。 – PatrickT 2011-12-21 16:07:23

+0

對不起,我不知道Python,我只知道它是一種受人尊敬的腳本語言,從我遇到的這些問題來看,它似乎比批處理文件語法更直觀。 – Hybrid 2011-12-22 10:21:35

0

您定義了delims=<space>,如果您想要保留您的線條,因爲它在第一個空格之後分開,所以這是一個壞主意。
您應該將其更改爲FOR /F "tokens=* delims=" ...

您的echo !str! >> testCleaned.mpl將始終爲每行添加一個額外的空間,最好使用echo(!str!>>testCleaned.mpl

您還將失去所有行中的所有空行和所有感嘆號。

您也可以嘗試的Improved BatchSubstitute.bat

+0

嗨jeb,非常感謝,我照你說的做了,但沒有幫助。我還沒有嘗試過改進的BatchSubstitute.bat。將盡快。非常感謝。請耐心等待。 – PatrickT 2011-12-21 14:56:37

+0

謝謝jeb,所以我遇到了上述問題,我的文件非常大,我想我需要比批處理文件更強大的工具... 11,226,123字節 - > 1,934頁openoffice! 大部分這些網頁包含有問題的字符串... – PatrickT 2011-12-21 16:55:53

2

下面的批處理文件對以前的解決方案可以處理的字符具有相同的限制;這些限制是所有批處理語言程序固有的。但是,如果文件很大,並且要替換的行不是太多,則該程序應該運行得更快。沒有替換字符串的行不會被處理,而是直接複製到輸出文件。

@echo off 
setlocal EnableDelayedExpansion 
set "oldString=[HFloat(undefined),HFloat(undefined),HFloat(undefined)]," 
set "newString=" 
findstr /N ^^ inFile.mpl > numberedFile.tmp 
find /C ":" <numberedFile.tmp> lastLine.tmp 
set /P lastLine=<lastLine.tmp 
del lastLine.tmp 
call :ProcessLines <numberedFile.tmp> outFile.mpl 
del numberedFile.tmp 
goto :EOF 

:ProcessLines 
set lastProcessedLine=0 
for /F "delims=:" %%a in ('findstr /N /C:"%oldString%" inFile.mpl') do (
    call :copyUpToLine %%a 
    echo(!line:%oldString%=%newString%! 
) 
set /A linesToCopy=lastLine-lastProcessedLine 
for /L %%i in (1,1,%linesToCopy%) do (
    set /P line= 
    echo(!line:*:=! 
) 
exit /B 

:copyUpToLine number 
set /A linesToCopy=%1-lastProcessedLine-1 
for /L %%i in (1,1,%linesToCopy%) do (
    set /P line= 
    echo(!line:*:=! 
) 
set /P line= 
set line=!line:*:=! 
set lastProcessedLine=%1 
exit /B 

如果您可以對其他解決方案運行計時測試併發布結果,我將不勝感激。

編輯:我改變了set /A lastProcessedLine+=linesToCopy+1行的等效,但更快set lastProcessedLine=%1

+0

使用SET/P讀取文件的任何解決方案都應列出其他限制:1)行限於1021個字符長2)尾隨控制字符將從每行中剝離3)文件必須使用Windows樣式行終止CRLF。 – dbenham 2011-12-29 02:42:24

+0

簡單的SET/P解決方案在每行上執行搜索/替換操作,對於給定的輸入文件而言具有恆定的性能,無論替換次數如何。隨着替代品數量的增加,這種複雜的SET/P解決方案將顯着減慢。如果替換次數最少,這種複雜的解決方案比簡單的解決方案稍微快一些,但如果有很多替代品,則解決方案的速度會更慢。我更喜歡簡單的方法。 – dbenham 2011-12-29 02:50:39

相關問題