在 Linux Bash 中提取括号内的复杂字符串

在 Linux Bash 中提取括号内的复杂字符串

我想通过 Linux bash 工具提取如下字符串:

XXAAGGHH (XXXXX) ERRTYTUUUI
AAAAAAAA ( %%))XX) $@@$&%^&&
AADDDDD$ (.SD F@* @) *$%^^&^&&&
AA^@%%^^ ()[))DS((]) RTTYUU

提取的分辨率应为:

XXXXX
  %%))XX
.SD F@* @
)[))DS((]

不幸的是,我无法采用 substr 因为字符串长度不固定。括号内可能有括号(可能不平衡)、空格或制表符(实际上这些是UTF-8乱码,但本地系统只能显示ascii。)

我使用的模式是“(”:空格+左括号表示左边界。“)”:空格+右括号表示右边界。

我尝试过 awk、sed 和 grep,但失败了。

你能给我一个提示吗?谢谢。

答案1

sed唯一的解决方案:

sed 's/.* (\(.*\)) .*/\1/g'

例子:

sed 's/.* (\(.*\)) .*/\1/g' myInput.txt 
XXXXX
 %%))XX
.SD F@* @
)[))DS((]

答案2

grep -Eo '\(.+\)' input | sed 's/^.//; s/.$//'

答案3

请注意,为了找出模式,简单地回显示例是开发解决方案的一种简单方法,我通常就是这样做的。这也让其他人可以在他们的控制台上尝试它,而无需创建文件。

Gawk唯一的解决方案:

echo 'XXAAGGHH (XXXXX) ERRTYTUUUI
AAAAAAAA ( %%))XX) $@@$&%^&&
AADDDDD$ (.SD F@* @) *$%^^&^&&&
AA^@%%^^ ()[))DS((]) RTTYUU' | gawk '{r=gensub(/^[^(]*\((.*)\)[^)]*$/,"\\1","g",$0);print r}'
XXXXX
 %%))XX
.SD F@* @
)[))DS((]

awk 唯一的解决方案:

echo 'XXAAGGHH (XXXXX) ERRTYTUUUI
AAAAAAAA ( %%))XX) $@@$&%^&&
AADDDDD$ (.SD F@* @) *$%^^&^&&&
AA^@%%^^ ()[))DS((]) RTTYUU' | awk '{gsub(/^[^(]*\(|\)[^)]*$/,"",$0);print $0}'
XXXXX
 %%))XX
.SD F@* @
)[))DS((]

sed 唯一的解决方案:

echo 'XXAAGGHH (XXXXX) ERRTYTUUUI
AAAAAAAA ( %%))XX) $@@$&%^&&
AADDDDD$ (.SD F@* @) *$%^^&^&&&
AA^@%%^^ ()[))DS((]) RTTYUU' | sed -r 's/^[^(]*\(|\)[^)]*$//g'
XXXXX
 %%))XX
.SD F@* @
)[))DS((]

或对于文件:

gawk '{r=gensub(/^[^(]*\((.*)\)[^)]*$/,"\\1","g",$0);print r}' input_file
# OR
awk '{gsub(/^[^(]*\(|\)[^)]*$/,"",$0);print $0}' input_file
# OR
sed -r 's/^[^(]*\(|\)[^)]*$//g'  input_file
# all output:
XXXXX
 %%))XX
.SD F@* @
)[))DS((] 

尝试以这种方式学习是一个非常糟糕的主意,但是,除了用头撞正则表达式来自己弄清楚之外,没有什么可以替代,否则你永远不会真正学习它们。在我看来,没有什么比编程中的正则表达式更有价值的长期学习了。

这些规则很简单:取所有不是 a 的 ( 开始该行,然后是第一个 (,并忽略或删除它,然后取所有不是 a ) 加上最后一个 ) 结束该行并忽略或删除那。您会注意到,在给出的答案中,在这种情况下有两个选项,切掉行的开头和结尾以给出所需的结果,或者通过忽略行的开头和结尾来获取所需的结果,然后打印结果。

请注意,一旦有了模式,使用什么语言或工具来实现它就不那么重要了。

相关内容