我有一个字符串就是这种格式:
"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"
如果我在JS,C#等编写正常的正则表达式,我就这样做
(?:"(.+?)"|'(.+?)'|(\S+))
迭代匹配组以获取每个字符串,理想情况下不带引号。我最终想要将每个值添加到一个数组中,所以在这个例子中,我最终得到一个数组中的3个项目,如下所示:
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
我无法弄清楚如何使用grep
或sed
或bash regex复制此功能。我尝试过像
echo "$email" | grep -oP "\"\K(.+?)(?=\")|'\K(.+?)(?=')|(\S+)"
这个问题在于虽然它模仿了捕获组的功能,但它并没有真正适用于倍数,所以我得到像
这样的捕获"Mike
H<michael.haken@email1.com>"
michael.haken@email2.com
如果我删除前面/后面的逻辑,我至少得到3个字符串,但第一个和最后一个仍然用引号括起来。在那种方法中,我将输出管道传输到read
,这样我就可以单独将每个字符串添加到数组中,但我可以打开其他选项。
编辑:
我认为我的输入示例可能令人困惑,它只是一个可能的输入。实际输入可以是任何数量的任何顺序的双引号,单引号或非引用(无空格)字符串。我提供的Javascript / C#正则表达式是我试图实现的真实行为。
答案 0 :(得分:3)
您可以使用Perl:
$ email='"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"'
$ echo "$email" | perl -lane 'while (/"([^"]+)"|(\S+)/g) {print $1 ? $1 : $2}'
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
或者在纯粹的Bash中,它有点罗嗦:
re='\"([^\"]+)\"[[:space:]]*|([^[:space:]]+)[[:space:]]*'
while [[ $email =~ $re ]]; do
echo ${BASH_REMATCH[1]}${BASH_REMATCH[2]}
i=${#BASH_REMATCH}
email=${email:i}
done
# same output
答案 1 :(得分:1)
你的第一个表达很好;只需注意引号(当\
存在时使用单引号)。最后用{sed。
"
$ echo $mail | grep -Po '".*?"|\S+' | sed -r 's/"$|^"//g'
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
答案 2 :(得分:1)
gawk + bash 解决方案(将每个项目添加到数组中):
email_str='"Mike H<michael.haken@email1.com>" michael.haken@email2.com "Mike H<hakenmt@email1.com>"'
readarray -t email_arr < <(awk -v FPAT="[^\"'[:space:]]+[^\"']+[^\"'[:space:]]+" \
'{ for(i=1;i<=NF;i++) print $i }' <<<$email_str)
现在,所有项目都在email_arr
访问第二项:
echo "${email_arr[1]}"
michael.haken@email2.com
访问第3项:
echo "${email_arr[3]}"
Mike H<hakenmt@email1.com>
答案 3 :(得分:0)
您可以使用sed
来实现这一目标,
$ sed -r 's/"(.*)" (.*)"(.*)"/\1\n\2\n\3/g' <<< "$EMAIL"
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
答案 4 :(得分:0)
使用gawk
您可以设置多行RS
。
awk -v RS='"|" ' 'NF' inputfile
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
答案 5 :(得分:0)
像这样修改你的正则表达式:
grep -oP '("?\s*)\K.*?(?=")' file
输出:
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
答案 6 :(得分:0)
使用GNU awk和FPAT
到 define fields by content :
$ awk '
BEGIN { FPAT="([^ ]*)|(\"[^\"]*\")" } # define a field to be space-separated or in quotes
{
for(i=1;i<=NF;i++) { # iterate every field
gsub(/^\"|\"$/,"",$i) # remove leading and trailing quotes
print $i # output
}
}' file
Mike H<michael.haken@email1.com>
michael.haken@email2.com
Mike H<hakenmt@email1.com>
答案 7 :(得分:0)
我能做到的是有效的,但并不像我想要的代码那样简洁:
arr=()
while read line; do
line="${line//\"/}"
arr+=("${line//\'/}")
done < <(echo $email | grep -oP "\"(.+?)\"|'(.+?)'|(\S+)")
这给了我一个捕获组的数组,并按任意顺序处理输入,用双引号或单引号括起来,如果它没有空格,则根本没有。它还提供了数组中没有包装引号的元素。感谢所有的建议。