This question has been asked a lot on stackoverflow, but I can't seem to be able to make it work. Any hints appreciated. Here is a text file (extension .mpl) containing offending text that needs to be removed:
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)));
I want to remove every instance of:
[HFloat(undefined),HFloat(undefined),HFloat(undefined)],
and there are thousands such instances!. Note: the square brackets and the comma are to be removed. There is no space, so I have pages and pages of:
[HFloat(undefined),HFloat(undefined),HFloat(undefined)],
[HFloat(undefined),HFloat(undefined),HFloat(undefined)],
[HFloat(undefined),HFloat(undefined),HFloat(undefined)],
I won't list here all my failed attempts. Below is the closest I've come:
@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
The above was strung together, as it were, from pieces of code found on the web, especially at stackoverflow, e.g. Problem with search and replace batch file
What it does is produce a truncated file, as follows:
plotsetup('ps', 'plotoutput = "plotfile.eps"', 'plotoptions' = "color=rgb,landscape,noborder");
!str!
Please don't hesitate to request clarifications. Apologies if you feel that this question has already been answered. I would very much appreciate if you would copy-paste the relevant code for me, as I have tried for several hours.
Bonus: can this automatic naming be made to work? "%%~nICleaned.mpl
"
You defined
delims=<space>
, that's a bad idea if you want to preserve your lines, as it splits after the first space.You should change this to
FOR /F "tokens=* delims=" ...
.Your
echo !str! >> testCleaned.mpl
will always append one extra space to each line, better useecho(!str!>>testCleaned.mpl
.You will also lose all empty lines, and all exclamation marks in all lines.
You could also try the code of Improved BatchSubstitute.bat
The Batch file below have the same restrictions of previous solutions on characters that can be processed; these restrictions are inherent to all Batch language programs. However, this program should run faster if the file is large and the lines to replace are not too much. Lines with no replacement string are not processed, but directly copied to the output file.
I would appreciate if you may run a timing test on this an other solutions and post the results.
EDIT: I changed the
set /A lastProcessedLine+=linesToCopy+1
line for the equivalent, but fasterset lastProcessedLine=%1
.I'm no expert on batch files, so I can't offer a direct solution to your problem.
However, to solve your problem, it might be simpler to use an alternative to batch files.
For example, I'd recommend using http://www.csscript.net/ (if you know C#). This tool will allow you to run C# files like batch files, but giving you the power to write your script using C#, instead of horrible batch file syntax :)
Another alternative would be python, if you know python.
But I guess the point is, that this kind of task may be easier in another programming language.
The biggest problem with your existing code is the
SetLocal enableDelayedExpansion
is missplaced - it should be within the loop afterset str=%%I
.Other problems:
ECHO is off
if any lines becomes empty or contains only spaces after substitutionOptimization issue - using
>>
can be relatively slow. It is faster to enclose the whole loop in () and then use>
Below is about the best you can do with Windows batch. I auto named the output as requested, doing one better - It automatically preserves the extension of the original name.
Known limitations
=
or!
, nor can it start with*
or~
!
<CR><LF>
even if original did notAll but the first limitation could be eliminated, but it would require a lot of code, and would be horrifically slow. The solution would require a character by character search of each line. The last limitation would require some awkward test to determine if the last line was newline terminated, and then last line would have to be printed using
<nul SET /P "ln=!ln!"
trick if no newline wanted.Interesting feature (or limitation, depending on perspective)
<LF>
will be converted to Windows style with lines ending with<CR><LF>
There are other solutions using batch that are significantly faster, but they all have more limitations.
Update - I've posted a new pure batch solution that is able to do case sensitive searches and has no restrictions on search or replacement string content. It does have more restrictions on line length, trailing control characters, and line format. Performance is not bad, especially if the number of replacements is low. http://www.dostips.com/forum/viewtopic.php?f=3&t=2710
Addendum
Based on comments below, a batch solution will not work for this particular problem because of line length limitation.
But this code is a good basis for a batch based search and replace utility, as long as you are willing to put up with the limitations and relatively poor performance of batch.
There are much better text processing tools available, though they are not standard with Windows. My favorite is sed within the GNU Utilities for Win32 package. The utilities are free, and do not require any installation.
Here is a sed solution for Windows using GNU utilities
Update 2013-02-19
sed may not be an option if you work at a site that has rules forbidding the installation of executables downloaded from the web.
JScript has good regular expression handling, and it is standard on all modern Windows platforms, including XP. It is a good choice for performing search and replace operations on Windows platforms.
I have written a hybrid JScript/Batch search and replace script (REPL.BAT) that is easy to call from a batch script. A small amount of code gives a lot of powerful features; not as powerful as sed, but more than enough to handle this task, as well as many others. It is also quite fast, much faster than any pure batch solution. It also does not have any inherent line length limitations.
Here is a batch script that uses my REPL.BAT utility to accomplish the task.
I use the
L
option to specify a literal search string instead of a regular expression, and theE
option to pass the search and replace strings via environment variables by name, instead of using string literals on the command line.Here is the REPL.BAT utility script that the above code calls. Full documentation is encluded within the script.