提问人:Sarah Weinberger 提问时间:11/14/2023 最后编辑:Wiktor StribiżewSarah Weinberger 更新时间:11/18/2023 访问量:75
在脚本中提取正则表达式捕获组
Extract Regex Capture Group in Script
问:
我正在编写一个 CSH 脚本并尝试从给定键的源字符串中提取文本。
!/bin/csh -f
set source = "Smurfs\n\tPapa\nStar Trek\n\tRenegades\n\tStar Wars\n\tThe Empire Strikes Back\n"
set toFind = "Star Trek"
set regex = "$toFind[\s]*?(.*?)[\s]*?"
set match = `expr $source : $regex`
echo $match
上面的代码不起作用,所以我遗漏了一些东西。我尝试将“星际迷航”目录放在里面而不是变量。我应该看到答案。如果我把“星球大战”而不是“星际迷航”放在一起,我应该看到.Regenages
The Empire Strikes Back
谷歌搜索显示了一个使用 grep 的可能解决方案,例如
match = `grep -Po '<something>' <<< $source
我不知道该放什么,我也不是grep的专家。<something>
在实际代码中,我正在从文件中读取文本。我只是在这里简化了事情。
思潮?
答:
0赞
Sarah Weinberger
11/15/2023
#1
以下是我问题的字面答案,因为我问了 csh 的问题,但是我使用 bash 编写了一个解决方案。
匹配正则表达式捕获组
我使用Tutorial Point进行调试。
mystring1=' asdf1@wxyz2 @@a!s#d@f@@ asdf2@wxyz2 b!t#e@g '
tofind='asdf1@wxyz2'
regex="${tofind}[[:space:]]*([.!@\#a-zA-Z0-9]+)"
[[ $mystring1 =~ $regex ]]
echo $'\n'
echo $'\n'
echo '***********************'
echo ${BASH_REMATCH[1]}
echo '***********************'
评论
0赞
Ed Morton
11/16/2023
mystring1=' asdf1@wxyz2 @@a!s#d@f@@ asdf2@wxyz2 b!t#e@g '
与问题中的文本不同,采用换行符+制表符分隔的格式。这是对与您提出的问题不同的问题的可能答案。set source = "Smurfs\n\tPapa\nStar Trek\n\tRenegades\n\tStar Wars\n\tThe Empire Strikes Back\n"
0赞
Sarah Weinberger
11/15/2023
#2
真正的解决方案使用文件作为源,因此:
set valueCapture=`cat /mypath/filename | grep -A1 "${tofind}" | grep -v "${tofind}" | xargs`
从字符串中查找捕获值的代码应为(未对其进行测试):
set valueCapture=`cat $source | grep -A1 "${tofind}" | grep -v "${tofind}" | xargs`
在这两种情况下,我希望找到的是:
设置为 find='asdf1@wxyz2'
零件将修剪掉空格。xargs
评论
0赞
Ed Morton
11/16/2023
当您几乎应该进行整行或全字段字符串匹配时,这是在整行中执行部分正则表达式匹配,如果两行中都出现相同的目标字符串,则会失败。
0赞
Paul Hodges
11/18/2023
此外,UUoC.放下并回声“$source”cat”。cat file
grep -A1 "${tofind}" file. From a string you might use
, but not
0赞
Ed Morton
11/16/2023
#3
既然你说你的实际输入在一个文件中,那么下面是你输出的文件:printf
$ cat file
Smurfs
Papa
Star Trek
Renegades
Star Wars
The Empire Strikes Back
以下是匹配和打印您想要的字符串的方法:
$ awk -v tgt='Star Trek' '{gsub(/^[[:space:]]+|[[:space:]]+$/,"")} $0==tgt{n=NR+1} NR==n' file
Renegades
$ awk -v tgt='Star Wars' '{gsub(/^[[:space:]]+|[[:space:]]+$/,"")} $0==tgt{n=NR+1} NR==n' file
The Empire Strikes Back
请参阅为什么使用-shell-loop-to-process-text-considered-bad-practice。
0赞
Paul Hodges
11/18/2023
#4
流水线可以做到,虽然不如 Ed 的单一进程。awk
$: toFind="Star Wars"; echo "$source" | grep -EA1 "$toFind" | tail -1
The Empire Strikes Back
$: toFind="Star Trek"; echo "$source" | grep -EA1 "$toFind" | tail -1
Renegades
$: echo "$source">file; toFind="Star Trek"; grep -EA1 "$toFind" file | tail -1
Renegades
A 会起作用。sed
$: toFind="Star Trek"; sed -n "/$toFind/{n
p}" file # should work with any version
Renegades
$: toFind="Star Wars"; sed -n "/$toFind/{n;p}" file # semicolon is GNU
The Empire Strikes Back
所有这些可能都值得细化您的正则表达式。
$: toFind="Star"; sed -n "/$toFind/{n;p}" file
Renegades
The Empire Strikes Back
$: toFind="Star"; sed -n "/^$toFind$/{n;p}" file
$: toFind="Star Trek"; sed -n "/^$toFind$/{n;p}" file
Renegades
$: toFind="Star Wars"; sed -n "/^$toFind$/{n;p}" file # fails because of the leading tab
最后一个可能意味着您必须允许第一个。
测试你的逻辑。
评论
expr
key[str]="value"
myKey=Renegades
csh
Star Trek="Renegade"
csh
arr[key]="value"
set arr = (one two three)
echo $arr[1] $arr[3]
sed
awk
expr
GNU coreutils 8.30
man expr
info '(coreutils) expr invocation'
csh
bash
zsh
man grep