使用 sed 去除字符串中的括号

3

我正在尝试使用sed(1)从字符串中删除括号,但仅当括号以特定字符串开头时。例如,我想将Song Name (f/ featured artist) (Remix)这样的字符串更改为Song Name f/ featuredartist (Remix)。我该如何实现这一点?

我目前正在尝试以下操作:

echo "Song Name (f/ featuredartist) (Remix)" | sed s/"(f\/ [a-z]*)"/"f\/ "/

但是这只会返回Song Name f/ (Remix)

还要注意:在f/)之间可以放置任何内容,不仅限于我的尝试中所示的[a-z]*


你需要使用捕获组(不确定在 sed 中是否可用,请查阅相关文档)。 - SJuan76
1
任何事都可以?是这样吗?那么(f/ (/f嵌套)特色艺术家)呢?它属于“任何事”。哪个括号是闭合的? - Kaz
1
如果你想处理任意嵌套,你不能使用正则表达式解决你的问题。 - Carl Norum
不要使用那些正则表达式是规则的常规表达式。然而,一些最近的工具有“正则”表达式,实际上并不是规则的。 - Kaz
@segfault 换句话说,嵌套还是被识别了,但内部的f/没有被处理。当然我是指 (f/ (f/ nested) featuredartist) 而不是 /f - Kaz
显示剩余2条评论
3个回答

4
这可能对你有用:
echo "Song Name (f/ featuredartist) (Remix)" | sed 's|(\(f/[^)]*\))|\1|'
Song Name f/ featuredartist (Remix)

这就完成了。谢谢!您介意简要解释一下sed命令中的语法吗?我对正则表达式有一般的了解,但希望能理解在sed命令中使用\1的用法。 - finiteloop
请点击这里查看解释(以及非常好的教程)。 - potong

1
echo 'Song Name (f/ featured artist) (Remix)' | sed 's/\(.*\)(\(f\/[^)]\+\))/\1\2/'

我猜您正在尝试类似于这里所解释的内容:http://www.grymoire.com/Unix/Sed.html#uh-4 然而,那行特定的代码未能去掉括号。 - finiteloop
@segfault,这个有什么问题吗?它在示例中可以工作。 - perreal
你在回复中给出的那行代码,在我的命令行中尝试运行时甚至都不起作用。 - finiteloop

1

TXR解决方案(http://www.nongnu.org/txr)。

@;; a texts is a collection of text pieces
@;; with no gaps in between.
@;;
@(define texts (out))@\
  @(coll :gap 0)@(textpiece out)@(end)@\
  @(cat out "")@\
@(end)
@;;
@;; recursion depth indicator
@;;
@(bind recur 0)
@;;
@;; a textpiece is a paren unit,
@;; or a sequence of chars other than parens.
@;; or, else, in the non-recursive case only,
@;; any character.
@;;
@(define textpiece (out))@\
   @(cases)@\
     @(paren out)@\
   @(or)@\
     @{out /[^()]+/}@\
   @(or)@\
     @(bind recur 0)@\
     @{out /./}@\
   @(end)@\
@(end)
@;;
@;; a paren unit consists
@;; of ( followed by a space-delimited token
@;; followed by some texts (in recursive mode)
@;; followed by a closing paren ).
@;; Based on what the word is, we transform
@;; the text.
@;;
@(define paren (out))@\
  @(local word inner level)@\
  @(bind level recur)@\
  @(local recur)@\
  @(bind recur @(+ level 1))@\
  (@word @(texts inner))@\
  @(cases)@\
    @(bind recur 1)@\
    @(bind word ("f/") ;; extend list here
           )@\
    @(bind out inner)@\
  @(or)@\
    @(bind out `(@word @inner)`)@\
  @(end)@\
@(end)
@;; scan standard input in freeform (as one big line)
@(freeform)
@(texts out)@trailjunk
@(output)
@out@trailjunk
@(end)

示例运行:

$ txr paren.txr -
a b c d
[Ctrl-D]
a b c d

$ txr paren.txr -
The quick brown (f/ ox jumped over the (f/ lazy) dogs). (
The quick brown ox jumped over the (f/ lazy) dogs. (

recur变量是一种动态作用域的技巧。在非嵌套情况下,texts模式函数只能识别任意单个字符,否则它将吞掉一个闭合括号。在paren中,我们使用嵌套级别仅在第一递归级别中出现f/时剥离括号。但是,我们无论如何都会识别括号的嵌套。 - Kaz
这让Perl和PCRE中的递归模式看起来很容易。 - tchrist
recur 的重新绑定使用临时变量 level 非常笨拙。我刚刚引入了一个 rebind 指令,可以一步完成这个过程:@(rebind recur @(+ 1 recur))。该表达式在先前的 recur 绑定可见的环境中进行求值,但是然后会建立一个新的 recur 绑定来获取该值。现在已经在 git 中,并且当然将在 TXR 63 中发布。 - Kaz
展示代码?今晚不行,对我来说太晚了。但是这里有一个简短的例子,可以匹配函数调用名称以及其可能嵌套的括号来限定其参数列表:/\w+ ( \( (?: [^()]++ | (?-1) )*+ \) )/x - tchrist
这个答案中的代码不仅匹配嵌套的括号,而且还有动作。只是匹配嵌套的括号可以使用像这样的模式函数:@(define paren)@(maybe)[@(coll)@(paren)@(until)]@(end)]@(end)@(end),它比一些串行线噪声更容易理解。(这来自于平衡括号任务,其中使用方括号:http://www.nongnu.org/txr/rosetta-solutions.html)。它将匹配像`[a[b c]d][e[]]这样的东西,并在输入中留下一个不匹配的后缀。如果你看到一个[,那么就收集括号内的东西,直到你看到]。然后匹配]`。 - Kaz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接