Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Regex 带有由可变字数组成的子字符串捕获组的正则表达式_Regex_Linux_Bash_Capture Group - Fatal编程技术网

Regex 带有由可变字数组成的子字符串捕获组的正则表达式

Regex 带有由可变字数组成的子字符串捕获组的正则表达式,regex,linux,bash,capture-group,Regex,Linux,Bash,Capture Group,使用以下改编自的Bash脚本: 并将它们解析为4-5个字段 例如,钙泊三醇-Daivonex乳膏50mcg/1g 30 g[1]应按如下字段划分: 钙泊三醇成分 Daivonex奶油品牌名称 50mcg/1g 30 g强度 1件装 空,因为[1]形式后面没有文本 但是,当我运行脚本时,没有匹配项 以下是隔离行中的正则表达式,换行符仅用于可读性: ^[[:alpha:][]+[:space:][:punt:][]+[:alpha:][:space:][:space:][+[:digit:][+[m

使用以下改编自的Bash脚本:

并将它们解析为4-5个字段

例如,钙泊三醇-Daivonex乳膏50mcg/1g 30 g[1]应按如下字段划分:

钙泊三醇成分 Daivonex奶油品牌名称 50mcg/1g 30 g强度 1件装 空,因为[1]形式后面没有文本 但是,当我运行脚本时,没有匹配项

以下是隔离行中的正则表达式,换行符仅用于可读性: ^[[:alpha:][]+[:space:][:punt:][]+[:alpha:][:space:][:space:][+[:digit:][+[mcg | mg | g][:space:][\/0-9a-zA-Z[:space:][]*[\[[]位:][:digit:][+[\]*$

您能告诉我如何匹配50mcg/1g 30 g这样的字符串并在${BASH_REMATCH[4]}中捕获它吗?

与您的情况一样,awk提供了一种更易于维护且速度更快的解决方案:

awk是最好的选择,因为您的输入基本上是基于字段的,将输入分解为字段是awk的亮点。要了解awk,请参阅或在系统上运行man awk或info awk

为了简单起见,并且与示例输入一致,所有行内空白都假定为空格;如果制表符也应该匹配,则用[[:blank:]替换正则表达式中的实例

下面是纯bash尝试的固定简化版本:

[[:alpha:][[:alpha:][:blank:][]*[:alpha:][]的实例用于捕获成分和品牌名称;该表达式捕获一个只有字母的单词的可变列表,这些单词之间用空格分隔,列表中至少包含一个两个字母的单词

简化的正则表达式通过将商标名称后面的所有内容匹配到以下内容来避免mcg/mg/g解析困难[使用[^[]+的包大小开始,不管它包含多少空格;因为这包括尾随空格,read稍后用于修剪该空格

如果您确实需要明确匹配mcg/mg/g以排除误报: 将[^[]+替换为[:digit:][.]+mcg | mg | g[/0-9a-zA-Z[:space:]* 将$BASH_重新匹配索引5替换为6,将4替换为5,因为出于技术原因,上面引入了一个新的捕获组-请参见下面的解释。 请注意如何使用与选项卡或空格匹配的[:blank:]来代替[:space:],因为后者也与新行匹配,根据定义,新行在此处不存在

您最初的尝试存在各种问题,其中一些问题已在对该问题的评论中指出:

[mcg | mg | g]应该是mcg | mg | g或mc | g,因为[mcg | mg | g]是一个:在这种情况下,一组字符中的任何一个匹配一个字符,因此实际上是匹配一个m、c、|或g字符

[:space:]使用非ASCII,Bash不会将其识别为字符类的一部分

不是问题本身,而是警告和简化机会:

您正在混合使用[:alpha:]和a-zA-Z,它们只能保证在ASCII范围内工作相同;要匹配外来字母,也请使用[:alpha:];相反,[:digit:]可以假设匹配非ASCII数字,因此[0-9]可能是更安全的选择。 在bash中不需要转义/在[…]内,因为/不是正则表达式元字符,也不用作bash中的正则表达式分隔符。 [\[]和[\]]表示文字[and]是不必要的复杂;请使用\[和\]。 主要的问题是,您似乎对括号表达式的工作方式有误解。例如,[[:digit:][+[mcg | mg | g][:space:][/0-9a-zA-Z[:space:][]*]是一个结构不良的单括号表达式,应该是多个独立的子表达式:

[[:digit:][.]+-一个括号表达式,用于匹配一系列数字和/或。例如,用于匹配0.5g

mcg | mg | g-一个括号内的子表达式捕获组,使用alternation |匹配三个标记中的任何一个;注意,在bash正则表达式中使用…总是会创建一个捕获组,即使您只需要括号作为优先级,所以在索引到${bash_REMATCH[@]}时也需要考虑这一点

[/0-9a-zA-Z[:space:][]*-另一个括号表达式,它匹配由/、十进制数字、ASCII字母和空白字符组成的任何可能的空字符

然后,连接这些子表达式应该匹配一个字符串,例如50mcg/1g 30 g,您可以按如下方式验证该字符串:
[50mcg/1g 30 g'=~[:digit:][.]+mcg | mg | g][0-9a-zA-Z[:space:][]*]&&echo MATCHED:>>${BASH_REMATCH[0]}您的输入不一致。@heemayl如果输入不一致,在前两个中,我看到5个可提取字段,而在后两个中,我看到4个。使您的输出特定。@heemayl 5个可提取字段是:[:alpha:]+,[:alpha:][:space:]+,[:digit:]+[mcg | mg | g]+[\/0-9a-zA-Z[:space:]*],[:digit:]]和[:alpha:]*最后一个可以为空[:space:]的最后一次出现时,你的冒号出现了一些奇怪的情况。而且,[mcg | mg | g]不是mcg或mg或g,它是一个括号表达式m或c 或g或|。你的意思可能是mcg | mg | g,可以写成mc??g。
#!/bin/bash

while IFS= read -r line || [[ -n "$line" ]]; do
if [[ "$line" =~ ^([[:alpha:]]+)[[:space:][:punct:]]+([[:alpha:][:space:]]+)[[:space:]]([[:digit:]+[mcg|mg|g][:space:][\/0-9a-zA-Z[:space:]]*])[\[]([[:digit:]]+)[\]]([[:alpha:]]*)$ ]]
then
 printf "Ingredient: %s\n" "${BASH_REMATCH[1]}"
 printf "Brand name: %s\n" "${BASH_REMATCH[2]}"
 printf "Strength: %s\n" "${BASH_REMATCH[3]}"
 printf "Pack size: %s\n" "${BASH_REMATCH[4]}"
 printf "Form: %s\n" "${BASH_REMATCH[5]}"
fi  
done < "${1:-/dev/stdin}"
Calcipotriol - Daivonex Cream 50mcg/1g 30 g [1]
Candesartan cilexetil - Atacand 4mg [30] capsule
Danazol - Azol 100mg [100] 
Dexamethasone - Dexmethsone 0.5g [1] tablet
awk -F' +- +|[][]' '
  { 
    name = $2; sub(" +[0-9.]+(mc?)?g.*", "", name)
    strength = substr($2, 1 + length(name)); sub("^ +", "", strength)
    form = ""
    if (NF > 3) { form = $NF; sub("^ +", "", form) }

    print "Ingredient:", $1
    print "Brand name:", name
    print "Strength:  ", strength
    print "Pack size: ", $3
    print "Form:      ", form
    print "---"
  }
' <<'EOF'
Calcipotriol - Daivonex Cream 50mcg/1g 30 g [1]
Candesartan cilexetil - Atacand 4mg [30] capsule
Danazol - Azol 100mg [100] 
Dexamethasone - Dexmethsone 0.5g [1] tablet
EOF
while IFS= read -r line || [[ -n "$line" ]]; do
  if [[ "$line" =~ ^([[:alpha:]][[:alpha:][:blank:]]*[[:alpha:]])[[:blank:][:punct:]]+([[:alpha:]][[:alpha:][:blank:]]*[[:alpha:]])[[:blank:]]+([^[]+)\[([0-9]+)\][[:blank:]]*([[:alpha:]]*)$ ]]
  then    
    printf "Ingredient: %s\n" "${BASH_REMATCH[1]}"
    printf "Brand name: %s\n" "${BASH_REMATCH[2]}"
    read -r strength <<<"${BASH_REMATCH[3]}"
    printf "Strength: %s\n" "$strength"
    printf "Pack size: %s\n" "${BASH_REMATCH[4]}"
    printf "Form: %s\n" "${BASH_REMATCH[5]}"
  fi  
done < "${1:-/dev/stdin}"