1

I'm trying to automate a slightly laborious process which is involved in running computational chemistry calculations with a couple of free pieces of software. I've managed to find answers to most of what I need to do, but I'm missing the last piece of the puzzle, probably because it's quite unusual, and I don't know if it's possible with my chosen language - batch files. I chose this partly because I've had difficulty in the past getting C++ or JavaScript to read or edit other files, and Batch (which was recommended by a friend) did this first time without any difficulty.

I've copied a representative sample of my input file below.

Text above

 $DATA  
Adenosine                                                                
C1     0
O           8.0      0.1319600000      7.8748100000      0.9316500000
    DZV     0

C           6.0     -0.5337400000      7.9322600000      2.1608300000
   DZV     0

N           7.0      1.4158500000      4.2659800000      1.3661200000
   DZV     0

H           1.0     -0.4456400000      8.9556600000      2.5897400000
   DZV     0

More coordinates below

I would like to be able to (for example) find the string O 8.0, and replace the contents of the next line with the contents of a text file. The format,

Atom           atomic charge            coordinates
   text
blank space

needs to remain - the blank space is essential.

An example of the end product is here (for oxygen and carbon; nitrogen and hydrogen have been omitted for brevity):

 $DATA  
Adenosine                                                                       
C1       0
O           8.0      0.1319600000      7.8748100000      0.9316500000
S   5
1      2266.1767785             -0.53431809926E-02
2       340.87010191            -0.39890039230E-01
3        77.363135167           -0.17853911985
4        21.479644940           -0.46427684959
5         6.6589433124          -0.44309745172
S   1
1         0.80975975668          1.0000000
S   1
1         0.25530772234          1.0000000
P   3
1        17.721504317            0.43394573193E-01
2         3.8635505440           0.23094120765
3         1.0480920883           0.51375311064
P   1
1         0.27641544411          1.0000000
D   1
1         1.2000000              1.0000000

C           6.0     -0.5337400000      7.9322600000      2.1608300000
S   5
1      1238.4016938              0.54568832082E-02
2       186.29004992             0.40638409211E-01
3        42.251176346            0.18025593888
4        11.676557932            0.46315121755
5         3.5930506482           0.44087173314
S   1
1         0.40245147363          1.0000000
S   1
1         0.13090182668          1.0000000
P   3
1         9.4680970621           0.38387871728E-01
2         2.0103545142           0.21117025112
3         0.54771004707          0.51328172114
P   1
1         0.15268613795          1.0000000
D   1
1         0.8000000              1.0000000

I've managed to successfully do find and replace for strings using the following code:

set "search=SearchItem"
set "replace=Replacement"
set "textfile=text.txt"
set "newfile=newfile.txt"
(for /f "delims=" %%i in (%textfile%) do (
    set "line=%%i"
    setlocal enabledelayedexpansion
    set "line=!line:%search%=%replace%!"
    echo(!line!
    endlocal
))>"%newfile%"
del %textfile%
rename %newfile%  %textfile%

I've found "Find a line in a file and replace the next line"-type code here: Find a line in a file and replace the next line But this doesn't quite work - the code seems to turn:

Atom           atomic charge            coordinates
   text
blank space

into:

blank space
replacement text
blank space

And it only does this for one atom.

  • Where is all the information for the replacements from? I mean, how to you specify what atom information needs to replaced by what? please [edit] your question and include such details there... – aschipfl Aug 22 '19 at 15:47

3 Answers3

2
@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q57608034.txt"
SET "filename2=%sourcedir%\q57608034_repl.txt"
SET "outfile=%destdir%\outfile.txt"

SET "col1=O"
SET "col2=8.0"

SET "replacenext="

(
FOR /f "tokens=1*delims=[]" %%s IN ('find /n /v "" "%filename1%"') DO (
 IF DEFINED replacenext (SET "replacenext="&TYPE "%filename2%
 ) ELSE (
  FOR /f "tokens=1,2" %%c IN ("%%t") DO IF "%%c"=="%col1%" IF "%%d"=="%col2%" SET "replacenext=Y"
  ECHO(%%t
 )
)
)>"%outfile%"

GOTO :EOF

You would need to change the settings of sourcedir and destdir to suit your circumstances. The listing uses a setting that suits my system.

I used a file named q57608034.txt containing your data for my testing.

I used a file named q57608034_repl.txt containing some dummy replacement data for my testing.

Produces the file defined as %outfile%

I'm working solely with your statement I would like to be able to (for example) find the string O 8.0, and replace the contents of the next line with the contents of a text file. The format,

Sadly, you've described the result, but not provided an example.

The code above will find the two target strings, then replace the following line with the contents of a file.

The outer loop uses as input the output of find... which prefixes each line with a line number in [brackets]. No line of the file will match "" since "" will not match any lines in the file (including empty lines). The /v reverses the condition, showing lines that do not match "" which is every line. the /n then prefixes each line with [number].

The resultant "input" is then tokenised using [] as delimiters and selecting tokens 1 to be assigned to %%s and * (which means the remainder of the line - the whole actual line read from the source file) to %%t.

Since replacenext is initialised to nothing (ie it becomes not defined) then the else part of the if statement is executed. This tokenises "%%t" - the literal string from the file and selects the first two columns (using the default delimiters Space , and ; into %%c and %%d. If these two values match those specified as variables col1 and col2 then replacenext is set to a value. %%t is then echoed, regurgitating the line read from the original file.

When the next line is read, replacenext may now be defined and if it is, the replacementt text is copied in from the replacement-text file, then replacenext is cleared and so the following lines will be interpreted again for matching col1 and col2.

The result of which is:

Text above

$DATA
Adenosine
C1     0
O           8.0      0.1319600000      7.8748100000      0.9316500000
Replacement Text

C           6.0     -0.5337400000      7.9322600000      2.1608300000
DZV     0

N           7.0      1.4158500000      4.2659800000      1.3661200000
DZV     0

H           1.0     -0.4456400000      8.9556600000      2.5897400000
DZV     0

More coordinates below
Magoo
  • 77,302
  • 8
  • 62
  • 84
  • Your response is far more detailed than I expected, thank you! Despite my omitting a possibly crucial example, the code works perfectly. however, for some reason when I change out the relevant words in the code for the carbon `C 6.0` or nitrogen `N 7.0` lines, nothing is altered. – Matthew Stevens Aug 22 '19 at 13:06
  • Worked fine for me. Try replacing the `for...%%c...` line with ` FOR /f "tokens=1,2" %%c IN ("%%t") DO >con ECHO 1 "%%c" "%col1%"&IF "%%c"=="%col1%" >con ECHO 2 "%%d" "%col2%"&IF "%%d"=="%col2%" >con ECHO 3 setting&SET "replacenext=Y"` (all one physical line) The `>con` redirects the following `echo` to the console rather than the file, the `&` logically concatenates commands. You should see the comparison stage-by-stage. I'd suggest that you use a censored data file like the literal example you've provided, else the console report may be overwhelming. – Magoo Aug 22 '19 at 13:49
  • Thank you for your help. I had forgotten to change `SET "col1=O"` to `SET "col1=C"`, which meant the computer couldn't find a line with `O 6.0`. Hence, since computers do exactly what you tell them to, nothing was changed. The expanded `for...%%c...` line enabled me to twig what was going on. – Matthew Stevens Aug 22 '19 at 15:00
0

Magoos good answer uses the usual techniques with find for numbering and
a flag variable which avoids delayedexpansion.

To detect the trigger lines you might also echo to findstr with it's RegEx capabilities or
just compare the begin of the line exactly:

:: Q:\Test\2019\08\22\SO_57608034.cmd
@Echo off
set "search=O           8"
set "textfile=text.txt"
set "newfile=newfile.txt"
set "insertfile=other.txt"
Set "SkipNextLine="

(for /f "tokens=1,* delims=]" %%h in ('find /N /V "" "%textfile%") do (
    if defined SkipNextLine (
       type "%insertfile%"
       Set "SkipNextLine="
    ) else (
        Echo:%%i|findstr /BC:"%search%" >NUL 2>&1 && Set SkipNextLine=yes
        Echo:%%i
    )
))>"%newfile%"
del "%textfile%"
rename "%newfile%"  "%textfile%"
0

Your question is pretty incomplete:

  • Do you want to perform several replacements? If so,
  • How do you specify the required replacements?
  • Why do you need to replace with a text file? Isn't enough a string?

I used my own ideas to resolve your missing requirements:

@echo off
setlocal EnableDelayedExpansion

rem Define the replacement set
set i=0
for %%a in (
      "O           8.0= Replace   X"
      "N           7.0=   Other   Y"
      "EndOfSet" ) do (
   set /A i+=1
   set "replace[!i!]=%%~a"
)

rem Initialize the replacement set
set /A i=1, repLen=15, repThis=0
set "search=%replace[1]%"

rem Process the file
(for /f "tokens=1* delims=:" %%a in ('findstr /N "^" test.txt') do (
   if !repThis! equ 1 (
      for /F "tokens=2 delims==" %%x in ("!search!") do echo %%x
      set /A i+=1, repThis=0
      for %%i in (!i!) do set "search=!replace[%%i]!"
   ) else (
      echo/%%b
      set "line=%%b"
      if "!line:~0,%repLen%!" == "!search:~0,%repLen%!" set "repThis=1"
   )
)) > newFile.txt

Output:

Text above

 $DATA  
Adenosine                                                                
C1     0
O           8.0      0.1319600000      7.8748100000      0.9316500000
 Replace   X

C           6.0     -0.5337400000      7.9322600000      2.1608300000
   DZV     0

N           7.0      1.4158500000      4.2659800000      1.3661200000
   Other   Y

H           1.0     -0.4456400000      8.9556600000      2.5897400000
   DZV     0

More coordinates below

Please note that the replacement set must be defined in the same order of the data file...

Aacini
  • 65,180
  • 12
  • 72
  • 108