我想通过 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 ) 加上最后一个 ) 结束该行并忽略或删除那。您会注意到,在给出的答案中,在这种情况下有两个选项,切掉行的开头和结尾以给出所需的结果,或者通过忽略行的开头和结尾来获取所需的结果,然后打印结果。
请注意,一旦有了模式,使用什么语言或工具来实现它就不那么重要了。