【问题标题】:sed substitute whitespace for dash only between specific character patternssed 仅在特定字符模式之间用空格替换破折号
【发布时间】:2018-04-07 09:07:12
【问题描述】:

我有这样一行:

原创

sometext1 sometext2 word:A12 B34 C56 sometext3 sometext4
sometext5 sometext6 word:A123 B45 C67 sometext7 sometext8
sometext9 sometext10 anotherword:(someword1 someword2 someword3) sometext11 sometext12

已编辑

asdjfkklj lkdsjfic kdiw:A12 B34 C56 lksjdfioe sldkjflkjd
lknal niewoc kdiw:A123 B45 C678 oknes lkwid 
cnqule nkdal anotherword:(kdlklks inlqok mncvmnx) unqieo lksdnf

期望的输出:

asdjfkklj lkdsjfic kdiw:A12-B34-C56 lksjdfioe sldkjflkjd
lknal niewoc kdiw:A123-B45-C678 oknes lkwid 
cnqule nkdal anotherword:(kdlklks-inlqok-mncvmnx) unqieo lksdnf

已编辑:这会更明确吗?但坦率地说,这比写sometext# 更难阅读和回答。我不知道人们的喜好。

我只想在字母字母后跟一些数字后用破折号替换空格,并用两个括号之间的单词之间的破折号替换空格。而不是该行中的任何其他空格。也希望对语法进行解释。

谢谢!

【问题讨论】:

  • 为什么sometext2 word 中的t2 w 之间没有空格,符合字母后跟数字的标准。是不是一定要多位数。它必须是一个有边界的字符吗?
  • 三个部分是否总是用破折号连接?
  • @123 sometext1 sometext2 只是表示一堆文本。我只是用数字来表明它们是不同的字符。第三个例子中不同的词组也是如此。
  • @Armali 不,可能有 3 个以上的组。第三个例子中的词组也是如此。

标签: bash sed character substitution digits


【解决方案1】:

这可能对你有用(GNU sed):

sed -r ':a;s/(A[0-9]+(-[A-Z][0-9]+)*) ([A-Z][0-9]+)/\1-\3/;ta;s/(\(\S+(-\S+)*) (\S+( \S+)*\))/\1-\3/;ta' file

使用正则表达式和反向引用迭代替换所需字符串中的空格。

【讨论】:

    【解决方案2】:

    这段代码运行良好

    darby@Debian:~/Scrivania$ cat test.txt | sed -r 's@\s+([A-Z][0-9]+)@-\1@g' | sed ':l s/\(([^ )]*\)[ ]/\1-/;tl'
    asdjfkklj lkdsjfic kdiw:A12-B34-C56 lksjdfioe sldkjflkjd
    lknal niewoc kdiw:A123-B45-C678 oknes lkwid 
    cnqule nkdal anotherword:(kdlklks-inlqok-mncvmnx) unqieo lksdnf
    

    解释我的正则表达式

    在第一个正则表达式中

    Options
    
    -r              Enable regex extended
    
    Pattern
    
    \s+             One or more space characters
    ([A-Z][0-9]+)   Submatch a uppercase letter and one or more digits
    
    Replace
    
    -              Dash character
    \1             Previous submatch
    
    Note
    
    The g after delimiters ///g is for global substitution.
    

    在第二个正则表达式中

    Pattern
    
    :l             label branched to by t or b
    tl             jump to label if any substitution has been made on the pattern space since the most recent reading of input line or execution of command 't'. If label is not specified, then jump to the end of the script. This is a conditional branch
    \(([^ )]*\)    match all in round brackets and stop to first space found
    [ ]            one space character
    
    Replace
    
    \1             Previous submatch
    -              Add a dash
    

    【讨论】:

    • 不适用于sometext5 sometext6 word:A123 B45 C678 D888 sometext7 sometext8sometext5 sometext6 word:A123 B45 sometext7 sometext8
    • 虽然这段代码 sn-p 可以解决问题,但including an explanation 确实有助于提高帖子的质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
    • 这样不需要猫:sed 's/ ([AZ])/-\1/g;:ls/(([^ )]*) /\1-/;tl' test.txt
    • 我现在意识到,在某些文本之后添加一个数字对某些人来说意味着在某些字符之后有一个数字。有些人将 sometext 从字面上理解为包含字符 s、o、m、e、t、e、x、t 的单词。我为混乱道歉。请原谅我在正则表达式中的新手。我在这里的上下文是 sometext# 代表一个字符串,它可能会或可能不会形成可读的单词,并且很可能与另一个 sometext# 完全不同,要么具有不同的字符,要么具有不同组合的相同字符,并且可能是不同的长度。我将编辑我的问题。
    • 现在我已经解释了我的代码。希望对你有帮助。
    【解决方案3】:

    您需要使用() 捕获第一个字母数字组和第二个组。然后你可以简单地使用反向引用 \1\2 替换所有:

    使用 sed 两次

    sed -E 's/(\b[A-Za-z][0-9]+) ([A-Z])/\1-\2/g' | sed -E 's/(\b[A-Za-z][0-9]+) ([A-Z])/\1-\2/g' 
    

    或使用 perl(lookahead(?=...)正则表达式不捕获第二组)

    perl -pe 's/(\b[A-Za-z][0-9]+) (?=[A-Z])/\1-/g'
    


    \b 工作边界
    [A-Za-z] 1 封信
    [0-9]+ 1 个或多个数字

    sed 不支持 lookaheadlookbehind 功能

    【讨论】:

    • 谢谢。但它只用破折号替换了第一个空格。 sometext1 word:A12-B34 C56 sometext2。请你改进一下你的表达方式吗?
    • 如果我第二次执行它,它就会起作用,替换第二个空格word:A12-B34-C56。但它不应该运行第二次,对吧?可以一次执行替换吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-20
    • 1970-01-01
    • 2013-12-11
    • 2012-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多