I have semicolon delimited CSV file. Some numerical values are stored with decimal point, for other data manipulation I need to use numbers with decimal comma. This should run for each file in the same folder on any Win machine. Any ideas?
I have tried PowerShell successfully on single file using this script
(Get-Content VER_ZdnSort201608-20160908210028original.csv) | ForEach-Object { $_ -replace "\.", "," } | VER_ZdnSort201608-20160908210028new.csv
But I can't seem to get it work with multiple files, also without replacing content without creating new files.
The data looks like this:
520100;2016-08-31;3197.90;N0401
520200;2016-08-31;6406.66;N0401
520430;2016-08-31;536.40;N0401
520800;2016-08-31;1547.70;N0401
...
Output should be like this:
520100;2016-08-31;3197,90;N0401
520200;2016-08-31;6406,66;N0401
520430;2016-08-31;536,40;N0401
520800;2016-08-31;1547,70;N0401
...
The following will search in a given folder for .csv files. It will then replace any . with , in all .csv files found, overwriting the new text to the same file.
Get-ChildItem -Path C:\Folder -Filter '*.csv' | ForEach-Object {
(Get-Content $_.FullName).Replace('.',',') | Out-File $_.FullName
}
The following script constitutes a pure batch-file solution:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for %%F in (%*) do (
for /F delims^=^ eol^= %%L in ('
type "%%~F" ^& ^> "%%~F" rem/
') do (
set "LINE=%%L"
setlocal EnableDelayedExpansion
>> "%%~F" echo(!LINE:.=,!
endlocal
)
)
endlocal
exit /B
Provide the paths to your CSV files as command line arguments. Supposing the script is named convert-decimal-point.bat and your CSV files are located in D:\Data, use this command line:
convert-decimal-point.bat "D:\Data\*.csv"
Here is a comprehensive solution that does not blindly replace every . by , but checks each field whether it truly contains a fractional number (an optional sign +/-, followed by any number of decimal digits, followed by ., followed by any number of decimal digits; for example 1.2, -.73, +12.584) or an exponential number (a fractional number, followed by E/e, followed by a sign +/-, followed by one or more decimal digits; for example, 1.2E-02, -.73e+5). This is the batch-file code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SEARCH=." & rem // (decimal point to search for)
set "_REPLAC=," & rem // (decimal point for replacing)
set "_SEPCHR=;" & rem // (field separator character)
rem // Predefine global variables here:
set "$HEADER=" & rem // (set to something to ignore first line)
for %%F in (%*) do (
for /F delims^=^ eol^= %%L in ('
type "%%~F" ^& ^> "%%~F" rem/
') do (
set "COLL=%_SEPCHR%" & set "LINE=%%L"
setlocal EnableDelayedExpansion
set "LINE=!LINE:"=""!^"
if "!LINE:**=!"=="!LINE!" (
if "!LINE:?=!"=="!LINE!" (
for %%I in ("!LINE:%_SEPCHR%=" "!") do (
endlocal
set "ITEM=%%~I"
call :PROCESS ITEM ITEM
setlocal EnableDelayedExpansion
for /F "delims=" %%C in (^""!COLL!!ITEM!%_SEPCHR%"^") do (
endlocal
set "COLL=%%~C"
setlocal EnableDelayedExpansion
)
)
) else set "COLL=%_SEPCHR%!LINE!%_SEPCHR%"
) else set "COLL=%_SEPCHR%!LINE!%_SEPCHR%"
set "COLL=!COLL:""="!^"
>> "%%~F" echo(!COLL:~1,-1!
endlocal
set "$HEADER="
)
)
endlocal
exit /B
:PROCESS rtn_string ref_string
setlocal EnableDelayedExpansion
set "#RET=%~1"
set "STR=!%~2!"
if not defined $HEADER (
if defined STR (
if "!STR:%_REPLAC%=!"=="!STR!" (
set "CHK=!STR:*%_SEARCH%=!%_SEARCH%"
set "CHK=!CHK:*%_SEARCH%=!"
if not defined CHK (
rem // Adapt regular expressions as needed:
(echo("!STR!" | > nul findstr /R ^
/C:"^\"[0-9]*\%_SEARCH%[0-9]*\" $" ^
/C:"^\"[+-][0-9]*\%_SEARCH%[0-9]*\" $" ^
/C:"^\"[0-9]*\%_SEARCH%[0-9]*[Ee][+-][0-9][0-9]*\" $" ^
/C:"^\"[+-][0-9]*\%_SEARCH%[0-9]*[Ee][+-][0-9][0-9]*\" $" ^
) && (
set "STR=!STR:%_SEARCH%=%_REPLAC%!"
)
)
)
)
)
for /F "delims=" %%S in (^""!STR!"^") do (
endlocal
set "%#RET%=%%~S"
)
exit /B
you can use this command :
$file = Get-Content c:\somewhere\file.csv |Out-String
$file.Replace(".",",") |Out-File c:\somewhere\file.csv
Related
I need to add a progressive number of fixed length at the beginning of each row in a txt file. For example:
0001 aaaaaaaaaaa
0002 bbbbbbbbbb
...
0010 gggggggggg
I created a .bat file to run a PowerShell which should solve the problem:
#echo off &setlocal
set "path=C:\Users..."
set "filein=%~1"
set "fileout=%filein%_out"
setlocal EnableDelayedExpansion
call %SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe -Command "& {(Get-Content %path%\%filein%.txt) |ForEach-Object {$_.Insert(0,($id++).PadLeft(10,'0'))} |Set-Content %path%\%fileout%.txt}"
But it doesn't work. Probably there's some syntax error.
($id++).PadLeft(10,'0') fails, because ($id++) is of type [int], not [string], and [int] has no .PadLeft() method.
Simply converting ($id++) to a string is enough:
($id++).ToString().PadLeft(10,'0')
Also note that your sample output has a space between the padded number and the content of the line, so you'd have to use:
$_.Insert(0, ($id++).ToString().PadLeft(10,'0') + ' ')
As an aside:
You don't need call in a batch file to call executables (call is only needed for calling other batch files, if you want the call to return).
The PowerShell executable is in the %PATH% by default, so you can invoke it by name only, i.e., powershell.exe.
since you added the [batch-file] tag - here is a pure Batch solution:
#echo off
setlocal enabledelayedexpansion
set count=0
(for /f "delims=" %%A in (input.txt) do (
set /a count+=1
set "index=00000!count!"
echo !index:~-4! %%A
))>Output.txt
Something like this might workout for you -
$id = 1
$files = Get-Content "\\PathToYourFile\YourFile.txt"
foreach ($file in $files)
{
$Padded = $id.ToString("0000000000");
$file.Insert(0, ($Padded));
$id++
}
Use the ToString() method, instead of PadLeft to add progressive number of fixed length zeroes. That is much simpler and hassle-free.
Also, doing the entire operation in PowerShell will be much simpler.
You can also do this in a single line like -
$i = 1
Get-Content "\\PathToYourFile\YourFile.txt" | % { $_.Insert(0, ($i.ToString("0000000000"))); $i++ } | Set-Content ".\NewFileout.txt"
Here is a pure batch file solution, which does not ignore empty lines and is safe against all characters, even exclamantion marks (!):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set /A "IDX=0"
> "output.txt" (
for /F "delims=" %%L in ('findstr /N "^" "input.txt"') do (
set /A "IDX+=0"
set "LINE=%%L"
setlocal EnableDelayedExpansion
set "IDX=0000!IDX!"
echo !IDX:~-4! !LINE:*:=!
endlocal
)
)
endlocal
exit /B
I have these a .txt with the below output and need this in a excel with column name as "Name, ID, Location, Role" and repective details below in their rows.
Name: Murali
ID: 485
location: Trichy
Role: AS
Name: John
ID: 584
location: NY
Role: AS
Name: Oisce
ID: 358
location: NBC
Role: AS
Thanks in advance!!
The following is a generic PowerShell v3+ solution that works with any field names of any number (assuming that the lines repeat with the same field names, in the same order); it transforms the input directly into a CSV file that can be opened in Excel:
# Determine input and output file.
$inFile = 'file.txt'
$outFile = 'file.csv'
# Extract the headers from the input file, using an ordered hashtable.
# Lines are read, and each line's 1st field is added as a key to the hashtable
# until a duplicate value is found in the 1st field.
$headers = [ordered] #{}
foreach($line in (Get-Content $inFile)) {
$colName = ($line -split ': ', 2)[0]
if ($headers.Contains($colName)) { break }
$headers.$colName = $null
}
# Construct the header row and send it to the output file.
# Choose a suitable character encoding.
"`"$($headers.Keys -join '","')`"" | Out-File -Encoding Utf8 $outFile
#`# Now loop over all lines and write the data rows.
$numCols = $headers.Count
$outLine = ''
$sep = ''
$i = 0
foreach($line in (Get-Content $inFile)) {
++$i # Count lines starting at 1.
$val = ($line -split ': ', 2)[1]
# Enclose the value in "...", if necessary.
if ($val -match '[ ,"]') { $val = "`"$($val -replace '"', '\"')`"" }
#`# Add to the output line at hand.
$outLine += $sep + $val
if ($i % $numCols -eq 0) { # Last column value.
# Complete output line assembled, append it to the file.
# Note that the -Encoding value must match the one above.
$outLine | Add-Content -Encoding Utf8 $outFile
$sep = ''
$outLine = ''
} else { # 1st or interior column value
$sep = ','
}
}
Here is a pure batch-file solution; provide the text file to reformat as a command line argument:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILES=%~1"
for /F "delims== eol==" %%E in ('2^> nul set $') do set "%%E="
for %%F in ("%_FILES%") do (
if /I "%%~xF"==".csv" (set "EXT=_NEW.csv") else set "EXT=.csv"
set "FLAG=#"
< "%%~F" set /P LONE=""
set "FILE=%%~F"
setlocal EnableDelayedExpansion
> "%%~dpnF!EXT!" (
for /F "tokens=1,* delims=: eol=:" %%K in ('type "!FILE!" ^& echo^(!LONE!') do (
endlocal
set "HEAD=%%K"
set "DATA=%%L"
if defined FLAG set "FLAG=,"
set "LINE=,"
setlocal EnableDelayedExpansion
if defined $!HEAD! (
for /F "tokens=1,* delims== eol==" %%G in ('set $') do (
endlocal
set "NAME=%%G"
set "ITEM=%%H"
setlocal EnableDelayedExpansion
for /F "tokens=1,* delims=: eol=:" %%E in ("!FLAG!"!NAME:*$^=!",:!LINE!"!ITEM!",") do (
endlocal
if defined FLAG set "FLAG=%%E"
set "LINE=%%F"
setlocal EnableDelayedExpansion
)
)
if defined FLAG (
echo(!FLAG:~1,-1!
echo(!LINE:~1,-1!
endlocal
set "FLAG="
) else (
echo(!LINE:~1,-1!
endlocal
)
for /F "delims== eol==" %%E in ('set $') do set "%%E="
setlocal EnableDelayedExpansion
)
if "!DATA:~,1!"==" " set "DATA=!DATA:~1!"
for /F "delims=" %%E in ("$!HEAD!=!DATA!") do (
endlocal
set "%%E"
setlocal EnableDelayedExpansion
)
)
)
endlocal
)
endlocal
exit /B
The output CSV file using your input file would look like:
"ID","location","Name","Role"
"485","Trichy","Murali","AS"
"584","NY","John","AS"
"358","NBC","Oisce","AS"
Update
Here is an improved version of the script that preserves the original order of fields as they first appear in the input file:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILES=%~1"
set "_RSLTS=%~2"
rem // Clear all dynamic variables:
for /F "delims==" %%E in ('2^> nul set #') do set "%%E="
for /F "delims==" %%E in ('2^> nul set $') do set "%%E="
rem // Loop through the given file(s) to resolve its/their path(s):
for %%F in ("%_FILES%") do (
if /I "%%~xF"==".csv" (set "FEXT=_NEW.csv") else set "FEXT=.csv"
set "FLAG=#"
< "%%~F" set /P LONE=""
set "FILE=%%~F"
set "RSLT=%%~dpnF"
set /A "IDX=0"
setlocal EnableDelayedExpansion
if defined _RSLTS (set "RSLT=con") else set "RSLT=!RSLT!!FEXT!"
rem // Write to output file all at once:
> "!RSLT!" (
rem /* Read input file line by line, repeat first line once again finally, because
rem this contains an already present header for sure and therefore initiates
rem returning the previously collected last output data row: */
for /F "tokens=1,* delims=: eol=:" %%K in ('type "!FILE!" ^& echo^(!LONE!') do (
endlocal
set "HEAD=%%K"
set "DATA=%%L"
if defined FLAG set "FLAG=,"
set "LINE=,"
set /A "IDX+=1"
setlocal EnableDelayedExpansion
rem /* Check if current header is already present; if so, begin collecting a
rem new data row and return the previously collected one: */
if defined $!HEAD! (
rem // Read dynamic variable corresponding to current header indirectly:
for /F "tokens=1,* delims==" %%G in ('set #') do (
for /F "tokens=1,* delims=:" %%E in ("!FLAG!"%%H",:!LINE!"!$%%H!",") do (
endlocal
if defined FLAG set "FLAG=%%E"
set "LINE=%%F"
setlocal EnableDelayedExpansion
)
)
rem /* Return the currently collected data row, together with the column
rem header row in case it is the first time: */
if defined FLAG (
echo(!FLAG:~1,-1!
echo(!LINE:~1,-1!
endlocal
set "FLAG="
) else (
echo(!LINE:~1,-1!
endlocal
)
rem // Clear all dynamic variables:
for /F "delims==" %%E in ('set #') do set "%%E="
for /F "delims==" %%E in ('set $') do set "%%E="
set /A "IDX=1"
setlocal EnableDelayedExpansion
)
rem // Remove leading white-spaces from data value:
for /F "tokens=* eol= " %%E in ("!DATA!") do (
endlocal
set "DATA=%%E"
setlocal EnableDelayedExpansion
)
rem /* Assign name of dynamic variable corresponding with current header to a
rem numeric dynamic variable for preserving the order of (first) headers: */
set "IDX=000!IDX!"
for /F "delims=" %%E in ("#!IDX:~-4!=!HEAD!") do (
endlocal
set "%%E"
setlocal EnableDelayedExpansion
)
rem // Assign data value to dynamic variable corresponding with current header:
for /F "delims=" %%E in ("$!HEAD!=!DATA!") do (
endlocal
set "%%E"
setlocal EnableDelayedExpansion
)
)
)
endlocal
)
endlocal
exit /B
The output CSV file using your input file would look like:
"Name","ID","location","Role"
"Murali","485","Trichy","AS"
"John","584","NY","AS"
"Oisce","358","NBC","AS"
Without a need to format this in Excel is simply done by separating your fields with a character like , or ; (depending on your language settings in Excel) and renaming the file to have the externsion .csv, eg "data.csv".
When you open the file from explorer Excel will open this file and arrange your data in columns and rows. You could format the layout in Excel and save it as a XLSX file.
Here your data formatted as CSV with , as separator
Name, id, location, role
Murali, 485, Trichy, AS
John, 584, NY, AS
Oisce, 358, NBC, AS
EDIT: because of the challenge of mklement0 here a one line Ruby solution, NOT PART OF THE ANSWER, I'm sure not the shortest or best solution, just a proof of concept
%(
Name: Murali
ID: 485
location: Trichy
Role: AS
Name: John
ID: 584
location: NY
Role: AS
Name: Oisce
ID: 358
location: NBC
Role: AS
).scan(/(^\w+):( \w+)/).transpose.each_with_index.map{|r,i|i==0 ? r.uniq.collect{|x| %("#{x.strip}") }.join(',') : r.each_slice(4).map{|s|s.collect{|x| %("#{x.strip}") }.join(',')}}.join("\n")
here split up by operation with explanation
s.scan(/(^\w+):( \w+)/) # array of arrays (key, value), based on regular expression
.transpose.each_with_index.map{|r,i| # transpose to array of headers and values, use Enumerator
i==0 ? # first line = headers
r.uniq.collect{|x| %("#{x}") }.join(',') # unique values, surround with "", join with ","
: # rest of the lines = data
r.each_slice(4).map{|s| # pieces of 4 items
s.collect{|x| %("#{x.strip}") } # surround with ""
.join(',')}} # join with ","
.join("\n") # join with new line char
Or a shorter variant (s contains the string to parse)
(s.lines[0..3].join.scan(/(^\w+): (\w+)/).transpose.first + s.lines.join.scan(/(^\w+): (\w+)/).transpose.last).each_slice(4).map{|a| %("#{a.join('","')}")}
EDIT2:
Reading from a file is as simple as Fire.read("data.txt").scan(..) etc.
I can read files in memory GB's big if necessary but yes Ruby has the lazy method which reads only the part that is needed at the moment.
You can also use eg File.foreach('data.txt').first(10) which stops at reading at the 10th line.
Didn't want to make it too complicated though.
See eg http://blog.honeybadger.io/using-lazy-enumerators-to-work-with-large-files-in-ruby/
How can I change some character (#,%,&,$) in the filename of multiple files in one folder and his sub-folders?
Ravi Thapliyal answer how to do that with PowerShell but just for the files in a specific folder (Replace or delete certain characters from filenames of all files in a folder).
I need to generalize that for all files in all folders in the selected one.
Your own answer will only change one char, here is a solution with an array RegEx in one go, remove the chars you want to keep from $replace.
[char[]]$replace = '!##$%^&*(){}[]":;,<>/|\+=`~ '''
$regex = ($replace | % {[regex]::Escape($_)}) -join '|'
Get-ChildItem -recurse |
ForEach {
if ($_.Name -match $RegEx){
Ren $_.Fullname -NewName $($_.Name -replace $RegEx, '_') -whatif
}
}
If the output looks ok, remove the -whatif
Edit removed -File option from Get-ChildItem as it requires a recent Powershell version and wasn't necessary.
Edit2 I regularly state that Rename-Item accepts piped input, so here is a more straight forward version:
[char[]]$replace = '!##$%^&*(){}[]":;,<>/|\+=`~ '''
$regex = ($replace | % {[regex]::Escape($_)}) -join '|'
Get-ChildItem -recurse |
Where-Object { $_.Name -match $RegEx} |
Rename-Item -NewName {$_.Name -replace $RegEx, '_'} -whatif
I found this answer from Dustin Malone:
Get-ChildItem -recurse -name | ForEach-Object { Move-Item $_ $_.replace(" ", "_") }
It gives an error but do the trick.
The task can also be accomplished by a Windows cmd script (batch-file) -- however, there are some limitations, unless appropriate work-arounds are implemented.
The following script replaces #, %, &, $, ( and ) in file names. You can add more characters except ^, !, = and ~, which cannot be processed (an if query lets the replacement be skipped in order to avoid syntax errors). If you provide characters with a code greater than 127 = 0x7F, you may probably need to switch the code page adequately (see the chcp command). Note that the script does not rename any files but only displays them, until you remove the upper-case ECHO command:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=D:\path\to\root\dir" & rem /* (assign `%~1` here instead for the script to
rem accept the root dir. as command line argument) */
set _CHAR="#" "%%" "&" "$" "(" ")" & rem // (a `%` sign needs to be doubled!)
set "_REPL=_" & rem // (replacement character or string; this may also be empty)
if not defined _ROOT set "_ROOT=."
for /R "%_ROOT%" %%F in ("*.*") do (
set "FILE=%%~F"
set "NAME=%%~nxF"
setlocal EnableDelayedExpansion
for %%C in (!_CHAR!) do (
if not "%%~C"=="^" if not "%%~C"=="!" if not "%%~C"=="=" if not "%%~C"=="~" (
set "NAME=!NAME:%%~C=%_REPL%!"
)
)
ECHO ren "!FILE!" "!NAME!"
endlocal
)
endlocal
exit /B
To replace also the characters ^ and !, the script needs to be extended a bit:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=D:\path\to\root\dir" & rem /* (assign `%~1` here instead for the script to
rem accept the root dir. as command line argument) */
set _CHAR="#" "%%" "&" "$" "(" ")" "^" "!" & rem // (a `%` sign needs to be doubled!)
set "_REPL=_" & rem // (replacement character or string; this may also be empty)
if not defined _ROOT set "_ROOT=."
for /R "%_ROOT%" %%F in ("*.*") do (
set "FILE=%%~F"
set "NAME=%%~nxF"
setlocal EnableDelayedExpansion
for %%C in (!_CHAR!) do (
if "%%~C"=="^" (
set "NAME=!NAME:^=^^!"
call set "NAME=%%NAME:^=%_REPL%%%"
) else if "%%~C"=="!" (
call set "NAME=%%NAME:^!=%_REPL%%%"
) else if not "%%~C"=="=" if not "%%~C"=="~" (
set "NAME=!NAME:%%~C=%_REPL%!"
)
)
ECHO ren "!FILE!" "!NAME!"
endlocal
)
endlocal
exit /B
To replace also the characters = and ~, the script needs to be extended much more:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=D:\path\to\root\dir" & rem /* (assign `%~1` here instead for the script to
rem accept the root dir. as command line argument) */
set _CHAR="#" "%%" "&" "$" "(" ")" "^" "!" "=" "~" & rem // (a `%` sign needs to be doubled!)
set "_REPL=_" & rem // (replacement character or string; this may also be empty)
set "$LEN="
if not defined _ROOT set "_ROOT=."
for /R "%_ROOT%" %%F in ("*.*") do (
set "FILE=%%~F"
set "NAME=%%~nxF"
setlocal EnableDelayedExpansion
for %%C in (!_CHAR!) do (
if "%%~C"=="^" (
set "NAME=!NAME:^=^^!"
call set "NAME=%%NAME:^=%_REPL%%%"
) else if "%%~C"=="!" (
call set "NAME=%%NAME:^!=%_REPL%%%"
) else if "%%~C"=="~" (
call :FAST NAME NAME "%%~C" "%_REPL%"
) else if "%%~C"=="=" (
call :SLOW NAME NAME "%%~C" "%_REPL%"
) else (
set "NAME=!NAME:%%~C=%_REPL%!"
)
)
ECHO ren "!FILE!" "!NAME!"
endlocal
)
endlocal
exit /B
:FAST rtn_string ref_string val_char val_repl
rem // This works for `~` and `*`, but NOT for `=`!
setlocal DisableDelayedExpansion
set "STR="
set "CHR=%~3"
if not defined CHR goto :FQUIT
setlocal EnableDelayedExpansion
set "CHR=!CHR:~,1!"
set "STR=!%~2!"
:FLOOP
if defined STR (
set "END=!STR:*%~3=!"
if not "!END!"=="!STR!" (
for /F "eol=%CHR% delims=%CHR%" %%L in ("!STR!") do (
for /F "delims=" %%K in (^""!END!"^") do (
endlocal
set "STR=%%L%~4%%~K"
setlocal EnableDelayedExpansion
)
)
goto :FLOOP
)
)
:FQUIT
for /F "delims=" %%K in (^""!STR!"^") do (
endlocal
set "STR=%%~K"
)
endlocal & set "%~1=%STR%"
exit /B
:SLOW rtn_string ref_string val_char val_repl
rem // This works even for `=`.
setlocal DisableDelayedExpansion
set "STR="
set "CHR=%~3"
set "RPL=%~4"
if not defined CHR goto :SQUIT
if not defined $LEN call :LEN $LEN RPL
setlocal EnableDelayedExpansion
set "CHR=!CHR:~,1!"
set "STR=!%~2!"
set /A "IDX=0"
:SLOOP
set /A "NXT=IDX+1"
if defined STR (
set "POS=!STR:~%IDX%,1!"
if defined POS (
if "!POS!"=="!CHR!" (
set "STR=!STR:~,%IDX%!!RPL!!STR:~%NXT%!"
set /A "NXT=IDX+$LEN"
)
set /A "IDX=NXT"
goto :SLOOP
)
)
:SQUIT
for /F "delims=" %%K in (^""!STR!"^") do (
endlocal
set "STR=%%~K"
set "$LEN=%$LEN%"
)
endlocal & set "%~1=%STR%" & set "$LEN=%$LEN%"
exit /B
:LEN rtn_length ref_string
setlocal EnableDelayedExpansion
set "STR=!%~2!"
if not defined STR (set /A LEN=0) else (set /A LEN=1)
for %%L in (4096 2048 1024 512 256 128 64 32 16 8 4 2 1) do (
if defined STR (
set "INT=!STR:~%%L!"
if not "!INT!"=="" set /A LEN+=%%L & set "STR=!INT!"
)
)
endlocal & set "%~1=%LEN%"
exit /B
I would like to search & replace the end of each line in my file.txt and delete the char before.
In other words, I have a redundant comma at end of each line, and it disturbs me when passing the data to Excel.
I can't delete all commas, since most of them are valuable. I just need to delete those at end of each line, since they make a blank cell.
I don't mind using a PowerShell gc command.
This is the simplest way to "delete the last char of each line" using a Batch file:
#echo off
setlocal EnableDelayedExpansion
(for /F "delims=" %%a in (file.txt) do (
set "line=%%a"
echo(!line:~0,-1!
)) > output.txt
This Batch file have a series of limitations: it removes empty lines and lines that start with semicolon, and remove exclamation marks from the lines. Each restriction can be fixed introducing a modification that eventually ends in a code similar to aschipfl's answer, but this code may be enough for your needs.
Here is a PowerShell script that will take file in.txt as input, remove the last character from each line, and output them to out.txt:
Get-Content "in.txt" | % { $_.Substring(0, ($_.Length - 1)) } | Out-File "out.txt"
Adding a simple test to check you are only deleting commas:
Get-Content "in.txt" | % {
if($_.Substring(($_.Length - 1), 1) -eq ",") {
$_.Substring(0, ($_.Length - 1))
} else {
$_
}
} | Out-File "out.txt"
Here is a pure batch-file solution:
The following code snippet removes the last character from each line in file.txt if it is , and writes the result into file_new.txt:
#echo off
setlocal EnableExtensions
> "file_new.txt" (
for /F usebackq^ delims^=^ eol^= %%L in ("file.txt") do (
setlocal DisableDelayedExpansion
set "LINE=%%L"
setlocal EnableDelayedExpansion
if "!LINE:~-1!"=="," (
echo(!LINE:~,-1!
) else (
echo(!LINE!
)
endlocal
endlocal
)
)
endlocal
The toggling of delayed environment variable expansion (see setlocal /? and set /? for help) is required to avoid trouble with some special characters.
The above approach removes empty lines from the file as for /F ignores them. To avoid this, use the following script:
#echo off
setlocal EnableExtensions
> "file_new.txt" (
for /F delims^=^ eol^= %%L in ('findstr /N /R "^" "file.txt"') do (
setlocal DisableDelayedExpansion
set "LINE=%%L"
setlocal EnableDelayedExpansion
set "LINE=!LINE:*:=!"
if "!LINE:~-1!"=="," (
echo(!LINE:~,-1!
) else (
echo(!LINE!
)
endlocal
endlocal
)
)
endlocal
This uses the fact that findstr /N /R "^" returns every line (even empty ones) of the given file and prefixes it with a line number plus :. Therefore no line appears to be empty to for /F. The line set "LINE=!LINE:*:=!" is inserted to remove that prefix (everything up to the first :) from each line prior to outputting.
I have a text file with id's separated by new line
I want this text file to be comma separated using Batch script
Refer my code below, this code generates Comma seperated string but still with new line. I want the comma seperated string in single line
#echo on & setlocal ENABLEDELAYEDEXPANSION
for /f "tokens=* delims=" %%a in (input.txt) do (
set /a N+=1
echo ^%%a^,>>output.txt
)
input.txt is
1
2
3
4
5
Output.txt should be
1,2,3,4,5
This is easier with PowerShell:
(Get-Content input.txt) -join ',' | Out-File output.txt
#echo off
setlocal enableextensions disabledelayedexpansion
set "first=1"
(for /f "delims=" %%a in (input.txt) do (
if not defined first ( set /p"=,%%a" ) else ( set /p"=%%a" & set "first=" )
)) <nul >output.txt