Aragon
Aragon

Reputation: 1551

script to replace all dots in a file with a space but dots used in numbers should not be replaced

How to replace all dots in a file with a space but dots in numbers such as 1.23232 or 4.23232 should not be replaced.

for example

Input:

abc.hello is with cdf.why with 1.9343 and 3.3232 points. What will 

Output:

abc_hello is with cdf_why with 1.9343 and 3.3232 point_ what will

Upvotes: 0

Views: 233

Answers (4)

Ed Morton
Ed Morton

Reputation: 204310

$ cat file
abc.hello is with cdf.why with 1.9343 and 3.3232 points. What will
this is 1.234.
here it is ...1.234... a number
.that was a number.

$ sed -e 's/a/aA/g' -e 's/\([[:digit:]]\)\.\([[:digit:]]\)/\1aB\2/g' -e 's/\./_/g' -e 's/aB/./g' -e 's/aA/a/g' file
abc_hello is with cdf_why with 1.9343 and 3.3232 points_ What will
this is 1.234_
here it is ___1.234___ a number
_that was a number_

Try any solution you're considering with that input file as it includes some edge cases (there may be more I haven't included in that file too).

The solution is basically to temporarily convert periods within numbers to some string that cannot exist anywhere else in the file so we can then convert any other periods to underscores and then undo that first temporary conversion.

So first we create a string that can't exist in the file by converting all as to the string aA which means that the string aB cannot exist in the file. Then convert all .s within numbers to aBs, then all remaining .s to _s then unwind the temporary conversions so aBs return to .s and aAs returns to as:

sed -e 's/a/aA/g'                                     #    a ->   aA  encode #1
    -e 's/\([[:digit:]]\)\.\([[:digit:]]\)/\1aB\2/g'  #  2.4 -> 2aB4  encode #2
    -e 's/\./_/g'                                     #    . ->    _   convert
    -e 's/aB/./g'                                     # 2aB4 ->  2.4  decode #2
    -e 's/aA/a/g'                                     #   aA ->    a  decode #1
    file

That approach of creating a temporary string that you KNOW can't exist in the file is a common alternative to picking a control character or trying to come up with some string you THINK is highly unlikely to exist in the file when you temporarily need a string that doesn't exist in the file.

Upvotes: 3

Kent
Kent

Reputation: 195219

since you tagged with vi, I guess you may have vim too? it would be a very easy task for vim:

:%s/\D\zs\.\ze\D/_/g

Upvotes: 0

iruvar
iruvar

Reputation: 23374

awk -v RS='[[:space:]]+' '!/^[[:digit:]]+\.[[:digit:]]+$/{gsub("\\.", "_")}; {printf "%s", $0RT}' file.txt

Upvotes: 0

bmk
bmk

Reputation: 14147

I think, that will do what you want:

sed 's/\([^0-9]\)\.\([^0-9]\)/\1_\2/g' filename

This will replace all dots that are not between two digits with an underscore (_) sign (you can exchange the underscore with a space character in the above command to get spaces in the output).

If you want to write the changes back into the file, use sed -i.

Edit:

To cover dots at the beginning resp. end of the line or directly before or after a number the expression becomes a bit more ugly:

sed -r 's/(^|[^0-9])\.([^0-9]|$)/\1_\2/g;s/(^|[^0-9])\.([0-9])/\1_\2/g;s/([0-9])\.([^0-9]|$)/\1_\2/g'

resp.:

sed 's/\(^\|[^0-9]\)\.\([^0-9]\|$\)/\1_\2/g;s/\(^\|[^0-9]\)\.\([0-9]\)/\1_\2/g;s/\([0-9]\)\.\([^0-9]\|$\)/\1_\2/g'

Upvotes: 1

Related Questions