1

I have a text file that contains lots of values on multiple lines with a different amount of spaces between values. Some spacing is 4, 6, 7, 9, etc. I have this code written but it only works for removing odd numbers of spaces (and leaving one space) which means that if I have 4 spaces between values (an even amount) I have no required space left.

Edit: max spacing is 13 and values per line are not the same.

Example text file:

123.000    345.555 @      777.4560000  1.55555         66.878444
333.444      555.4848     999.758584 |    34.3737373

This is what I want after the fix:

123.000 345.555 777.4560000 1.55555 66.878444
333.444 555.4848 999.758584 34.3737373

This is what I am getting with my code below:

123.000345.555 777.45600001.55555 66.878444
333.444555.4848 999.758584 34.3737373

How do I set spacing to one space between every value regardless of the amount of spaces? I am also removing the @ and | symbols as well.

 @echo off
 setlocal EnableExtensions DisableDelayedExpansion
 > "conv_output_clean.txt" (
     for /F "usebackq delims=" %%L in ("conv_output.txt") do (
         set "LINE=%%L"
         setlocal EnableDelayedExpansion
         set "LINE= !LINE:  =!"
         set "LINE=!LINE:@=!"
         set "LINE=!LINE:|=!"
        echo(!LINE!
        endlocal
    )
 )
 endlocal
 exit /B
paisak
  • 13
  • 4
  • Is there a set number of values on each line? You can use `for` to see multiple delimiters as a single delimiter. – avery_larry Jul 23 '20 at 21:38
  • Unfortunately no there is not. I checked to make sure. – paisak Jul 23 '20 at 21:40
  • How about a maximum number of spaces between values? There's probably a more elegant solution but we could loop enough times to guarantee all double spaces are removed. Or probably use a binary progression (or whatever it's called). – avery_larry Jul 23 '20 at 21:42
  • It looks like 13 is the max number of spaces. So do I add another for loop inside to remove double spaces? How would I do this? – paisak Jul 23 '20 at 21:49
  • There is a vertical bar, in your text file which you appear to want removed, but you did not mention it? Is this part of your question, or are we supposed to ignore it? – Compo Jul 23 '20 at 22:07
  • My last set command removes the bar correctly. – paisak Jul 23 '20 at 22:18

7 Answers7

1

Based upon your provided text content, and ignoring your | and @ characters being removed, the following example should replace all concurrent space characters with a single one:

@SetLocal EnableDelayedExpansion
@(For /F UseBackQ^ Delims^=^ EOL^= %%G In ("conv_output.txt") Do @(Set "_="
    For %%H In (%%G) Do @If Not Defined _ (Set "_=%%H ") Else Set "_=!_!%%H "
    Echo !_!)) 1> "conv_output_clean.txt"

If you want to also remove the | and @ characters, then the following modification should work with your provided content:

@SetLocal EnableDelayedExpansion
@(For /F UseBackQ^ Delims^=^ EOL^= %%G In ("conv_output.txt") Do @(
    Set "_="&Set "#=%%G"&Set "#=!#:|=!"
    For %%H In (!#:@^=!) Do @If Not Defined _ (Set "_=%%H ") Else Set "_=!_!%%H "
    Echo !_!)) 1> "conv_output_clean.txt"
Compo
  • 36,585
  • 5
  • 27
  • 39
  • I have two set commands in my original code that removed the @ and the | symbol. – paisak Jul 23 '20 at 23:01
  • @paisak, to additionally remove the `|` and `@` characters, I have included an alternative solution in my answer above. – Compo Jul 23 '20 at 23:10
  • Very clean answer, Compo! It worked perfectly to solve my problem. – paisak Jul 23 '20 at 23:22
  • 1
    Just remember, @paisak, this site is supposed to be for assistance with a single issue with your provided code. Your question title, and body, are that question, which is about replacing a series of space characters with a single one. That is why I answered initially to do that. As you can see from my modified additional version, the other parts were just trivial additions, using variable expansion and replacement, which you already showed you knew how to do, and therefore do not really form part of your question. – Compo Jul 23 '20 at 23:24
1

Yet another way, output redirection left for the reader to add.

@echo off
setlocal EnableExtensions EnableDelayedExpansion

for /F "usebackq delims=" %%L in ("conv_output.txt") do (
  set "line="
  for %%M in (%%L) do (
    if "%%M" neq "@" if "%%M" neq "|" (
      if defined line set "line=!line! "
      set "line=!line!%%M"
    )
  ) 
  echo(!line!
)

[ EDIT ] Sample run output.

C:\etc>type conv_output.txt
123.000    345.555 @      777.4560000  1.55555         66.878444
333.444      555.4848     999.758584 |    34.3737373

C:\etc>conv_output.cmd
123.000 345.555 777.4560000 1.55555 66.878444
333.444 555.4848 999.758584 34.3737373

C:\etc>
dxiv
  • 16,984
  • 2
  • 27
  • 49
  • Your code seems to give me the last line of my text file only with the correct parsing. – paisak Jul 23 '20 at 23:23
  • @paisak It's getting all the lines correctly AFAICT, see the added edit. – dxiv Jul 23 '20 at 23:31
  • use `useback^ delims^=^ eol^=` to not skip lines that start with `;` – ScriptKidd Jul 24 '20 at 12:59
  • @HackingAddict1337 This was meant as an answer to OP's question, which it is, nothing less and nothing more. None of the answers posted thus far covers all possible cases, and none pretends to be a generic token parser. For example, Squashman's answer also ignores comment lines starting with a `;`, and all others mishandle lines containing `^ ^^ ^^^`. – dxiv Jul 24 '20 at 16:19
  • @dxiv the good practice i gave in the comments was harmless. `^` can be solved by toggling between delayed exoansion – ScriptKidd Jul 26 '20 at 12:45
0

You can wind down number of spaces step by step using a while-like loop (or until-like loop). Unfortunately, we cannot use :label inside a command block enclosed in () parentheses so call a subroutine as follows:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
>"conv_output_clean.txt" (
  for /F "usebackq delims=" %%L in ("conv_output.txt") do (
    set "LINE=%%L"
    call :removeAddChars
    setlocal EnableDelayedExpansion
      echo(!LINE!
    endlocal
  )
)
endlocal
exit /B
 
:removeAddChars
set "LINE=%LINE:@=%"
set "LINE=%LINE:|=%"
:remove2Spaces
set "LINE=%LINE:  = %"
set "_LINE=%LINE:  = %"
if "%_LINE%"=="%LINE%" goto :eof
goto :remove2Spaces

Output:

type conv_output.txt
123.000    345.555 @      777.4560000  1.55555         66.878444
333.444      555.4848     999.758584 |    34.3737373
.\SO\63063411.bat
type conv_output_clean.txt
123.000 345.555 777.4560000 1.55555 66.878444
333.444 555.4848 999.758584 34.3737373
JosefZ
  • 28,460
  • 5
  • 44
  • 83
  • Brilliant!! That worked perfectly! Thank you for the links as well. I am learning as I go and that helped a ton. – paisak Jul 23 '20 at 22:17
0

This will work with up to 16 spaces:

@echo off
setlocal enabledelayedexpansion

for /f "usebackq delims=" %%a in ("conv_output.txt") do (
   set "LINE=%%~a"
   set "LINE=!LINE:@=!"
   set "LINE=!LINE:|=!"
   set "LINE=!LINE:         = !"
   set "LINE=!LINE:     = !"
   set "LINE=!LINE:   = !"
   set "LINE=!LINE:  = !"
   echo !line!
)

It replaces 9 spaces with a single space, then 5, 3, and 2. If you add 17 you can (I believe) replace up to 32 spaces. Note it is imperative to remove the @ and | first.

Another idea is to use call and shift:

@echo off
setlocal enabledelayedexpansion
for /f "usebackq delims=" %%a in ("conv_output.txt") do (
   set "lineinput=%%~a"
   set "lineinput=!lineinput:@=!"
   set "lineinput=!lineinput:|=!"
   call :process !lineinput!
)
goto :eof

:process
set lineoutput=%~1
shift
:loop
if "%~1"=="" echo %lineoutput%&&goto :eof
set lineoutput=%lineoutput% %~1
shift
goto :loop

I'll leave it up to you to put this into your code.

avery_larry
  • 2,069
  • 1
  • 5
  • 17
  • I like your answers. I will keep them in my bag of tricks. Thank you for taking the time to answer my questions. – paisak Jul 23 '20 at 22:41
0

Here is one more algorithm as designed by Jeb on DosTips.com

@echo off
 setlocal EnableExtensions DisableDelayedExpansion
 > "conv_output_clean.txt" (
    for /F "usebackq delims=" %%L in ("conv_output.txt") do (
        set "str=%%L"
        setlocal EnableDelayedExpansion
        set "str=!str:@=!"
        set "str=!str:|=!"
        set ^"str=!str: =a  !"
        set ^"str=!str: a =!"
        set ^"str=!str:a  = !"
        echo(!str!
        endlocal
    )
)
endlocal
exit /B

Here is Jeb's explanation from that post. In Jeb's example it was replacing commas. So wherever he mentions a comma, it equates to the space in this users desired output

I want to use the replacing of a search pattern with nothing to remove all but one comma.
Obviously this can't work with simply replacing ","->"".
So I create first a better pattern
"," -> "a,,"
abc,,,,cba,,,,end
will be expanded to
abca,,a,,a,,a,,cbaa,,a,,a,,a,,end
Then each ",a," will be replaced with nothing
abca,,a,,a,,a,,cbaa,,a,,a,,a,,end
->
abca,,cbaa,,end

Now, exactly one pattern remains and will be replaced with the rule "a,," -> ","

And just to show the efficiency of some of the code answers, I did a test with a 2,000 line file.

JosezF: 0 Days 0 Hours 0 Minutes And 5 Seconds
Jeb: 0 Days 0 Hours 0 Minutes And 0 Seconds
Compo: 0 Days 0 Hours 0 Minutes And 0 Seconds

The code I used from Jeb and Compo's code are quite efficient. Less than 1 second for each of them.

Squashman
  • 13,649
  • 5
  • 27
  • 36
0

Here is an alternative approach that is foolproof against empty lines/ lines that contain !

@echo off
SETLOCAL DisableDelayedExpansion EnableExtensions


>"process.txt" (FOR /F "delims=" %%L in ('
""%__APPDIR__%FINDSTR.EXE" /N "^^" example.txt"
') do (
    set "lnCont=%%L"
    SETLOCAL EnableDelayedExpansion
    set "lnCont=!lnCont:*:=!"
    
    FOR %%C in (^| @) do if DEFINED lnCont set "lnCont=!lnCont:%%~C=!"
    if DEFINED lnCont FOR /F delims^=^ eol^= %%T in (^"!lnCont:^ ^=^
%=DO NOT REMOVE ME=%
!^") do if DEFINED proc (set "proc=!proc! %%T") ELSE set "proc=%%T"
    echo(!proc!
    
    ENDLOCAL
))

The loop:

  1. parses the output of FINDSTR /N, line by line
  2. replace all SPACEs with linefeeds
  3. FOR /F ignore empty lines, therefore consecutive spaces are treated as one
ScriptKidd
  • 803
  • 1
  • 5
  • 19
0

One more way...

Get-Content .\conv_output.txt |
    ForEach-Object { ($_ -replace '\|','') -replace '\s+',' ' }

Running from a cmd.exe shell or .bat file script...

powershell -NoLogo -NoProfile -Command ^
    "Get-Content .\conv_output.txt |" ^
        "ForEach-Object { ($_ -replace '\|','') -replace '\s+',' ' }"
lit
  • 14,456
  • 10
  • 65
  • 119