【问题标题】:script to replace all dots in a file with a space but dots used in numbers should not be replaced用空格替换文件中所有点的脚本,但不应替换数字中使用的点
【发布时间】:2013-11-28 19:33:43
【问题描述】:

如何用空格替换文件中的所有点,但不应替换数字中的点,例如 1.232324.23232

例如

输入:

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

输出:

abc_hello is with cdf_why with 1.9343 and 3.3232 point_ what will

【问题讨论】:

    标签: unix scripting replace awk vi


    【解决方案1】:
    $ 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_
    

    使用该输入文件尝试您正在考虑的任何解决方案,因为它包含一些边缘情况(可能还有更多我没有包含在该文件中)。

    解决方案基本上是将数字中的句点临时转换为文件中其他任何地方都不存在的字符串,这样我们就可以将任何其他句点转换为下划线,然后撤消第一次临时转换。

    所以首先我们通过将所有as 转换为字符串aA 来创建文件中不存在的字符串,这意味着文件中不存在字符串aB。然后将数字中的所有.s 转换为aBs,然后将所有剩余的.s 转换为_s,然后展开临时转换,使aBs 返回到.s 并且aAs 返回到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
    

    创建您知道文件中不存在的临时字符串的方法是选择控制字符或尝试提出一些您认为文件中不太可能存在的字符串的常见替代方法需要一个文件中不存在的字符串。

    【讨论】:

      【解决方案2】:

      既然你标记了vi,我猜你可能也有vim?这对 vim 来说是一件很容易的事:

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

      【讨论】:

      • 在行首和行尾的句点、连续的句点链以及可能的其他情况下都会失败。在我在答案中发布的输入文件上尝试一下。
      【解决方案3】:

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

      【讨论】:

      • 不会在行首或数字后处理句点
      • @EdMorton,我想我通过编辑修复了它,但话又说回来,我更喜欢你的解决方案,+1。
      • 谢谢。您的更新版本更接近,但如果数字和其他文本之间没有空格,则会错误地转换数字中的句点,请尝试使用我发布的输入文件并注意输入的第 2 行和第 3 行中的数字会发生什么变化。跨度>
      【解决方案4】:

      我认为,这会做你想要的:

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

      这会将不在两位数之间的所有点替换为下划线 (_) 符号(您可以在上述命令中将下划线与空格字符交换以获取输出中的空格)。

      如果要将更改写回文件中,请使用sed -i

      编辑:

      分别覆盖开头的点。行尾或直接在数字之前或之后,表达式变得更难看:

      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'
      

      分别:

      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'
      

      【讨论】:

      • 不会处理行首或行尾或数字前后的句点。
      • 更新后的解决方案不会处理连续的句点序列。
      • @EdMorton:好的 - 我不得不承认 - 你发现了一个我无法用我的方法涵盖的特殊情况。
      • 我不认为在文本中找到一系列句点有什么特别之处(I wonder.... could it be special?),这只是另一个典型的边缘情况。 “特殊”(我认为您的意思是不太可能)我认为可能是行首的句号,但是您会在输入错误的句子中得到它,并且谁知道OP正在处理什么...(哎呀,那里他们又来了。)。
      猜你喜欢
      • 2011-05-02
      • 1970-01-01
      • 2021-10-05
      • 1970-01-01
      • 1970-01-01
      • 2019-06-27
      • 1970-01-01
      • 1970-01-01
      • 2012-12-16
      相关资源
      最近更新 更多