代码之家  ›  专栏  ›  技术社区  ›  Poshi

应用替换n次

  •  3
  • Poshi  · 技术社区  · 6 年前

    我有一根绳子

    data1_data2_data3_data4@data5,data6
    

    有时,数据5包含下划线,而下划线恰好是字段分隔符。丑,我知道。

    我想用如下方式阅读这些数据:

    IFS="_@," read d1 d2 d3 d4 d5 d6 <<< "$input"
    

    当数据5包含下划线时,问题就出现了。解决这个问题。我想用逗号替换前三个下划线(还有@)。到目前为止,我发现最简单的方法是和塞德在一起:

    sed 's/_/,/; s/_/,/; s/_/,/; s/@/,/' <<< "$input"
    

    但是重复三次相同的替换看起来效率很低。如果我需要重复5000次会发生什么?

    有没有办法告诉塞德重复替换一定次数?

    要完成,请输入示例:

    input="data1_data2_data3_data4@d_a_t_a_5,data6"
    IFS="," read d1 d2 d3 d4 d5 d6 <<< "$input"
    

    预期输出:

    d1=="data1"
    d2=="data2"
    d3=="data3"
    d4=="data4"
    d5=="d_a_t_a_5"
    d6=="data6"
    
    5 回复  |  直到 6 年前
        1
  •  1
  •   anubhava    6 年前

    你可以用这个 awk 在流程替换中:

    input="data1_data2_data3_data4@d_a_t_a_5,data6"
    
    IFS=, read d1 d2 d3 d4 d5 d6 < <(awk -F@ -v OFS=, -v n=3 '{
    while (i++<n) sub(/_/, ",", $1)} 1' <<< "$input")
    
    # check variable values
    declare -p d1 d2 d3 d4 d5 d6
    

    declare -- d1="data1"
    declare -- d2="data2"
    declare -- d3="data3"
    declare -- d4="data4"
    declare -- d5="d_a_t_a_5"
    declare -- d6="data6"
    
    • AWK 命令使用 @ 作为字段分隔符。
    • 锥子 命令替换 _ 具有 , 在里面 仅第一字段 确切地 n 时代。
        2
  •  1
  •   oguz ismail    6 年前

    使用AWK。

    $ input="data1_data2_data3_data4@d_a_t_a_5,data6"
    $ awk -v RS='[@\n]' '{ if(NR % 2){ gsub(/_/, ","); ORS = "," } else ORS = "\n" } 1' <<< "$input"
    data1,data2,data3,data4,d_a_t_a_5,data6
    
        3
  •  0
  •   Nahuel Fouilleul    6 年前

    可以选择使用shell扩展手动拆分 ${var%%pat} 条带最大后缀匹配pat和 ${var#pat} 条带最短前缀匹配pat

    while IFS= read line; do
        tmpline=$line
        d1=${tmpline%%_*} tmpline=${tmpline#*_}
        d2=${tmpline%%_*} tmpline=${tmpline#*_}
        d3=${tmpline%%_*} tmpline=${tmpline#*_}
        d4=${tmpline%%@*} tmpline=${tmpline#*@}
        d5=${tmpline%%,*} tmpline=${tmpline#*,}
        d6=${tmpline}
    
        printf "%s\n" "d1=$d1" "d2=$d2" "d3=$d3" "d4=$d4" "d5=$d5" "d6=$d6"
    done <<< "$input"
    

    或者为了绕过bash读取速度慢,手动拆分行

    tmpinput=$input
    while [[ $tmpinput ]]; do
        if [[ $tmpinput = *$'\n'* ]]; then
            tmpline=${tmpinput%%$'\n'*} tmpinput=${tmpinput#*$'\n'}
        else
            tmpline=${tmpinput} tmpinput=''
        fi
    
        d1=${tmpline%%_*} tmpline=${tmpline#*_}
        d2=${tmpline%%_*} tmpline=${tmpline#*_}
        d3=${tmpline%%_*} tmpline=${tmpline#*_}
        d4=${tmpline%%@*} tmpline=${tmpline#*@}
        d5=${tmpline%%,*} tmpline=${tmpline#*,}
        d6=${tmpline}
    
        printf "%s\n" "d1=$d1" "d2=$d2" "d3=$d3" "d4=$d4" "d5=$d5" "d6=$d6"
    done 
    
        4
  •  0
  •   chepner    6 年前

    bash ,我将改用正则表达式。

    $ cat input
    one_two_three_fourpt1_fourpt2@fivept1_fivept2,six
    $ regex='([^_]+)_([^_]+)_([^_]+)_(.+)@([^,]+).(.*)'
    $ while IFS= read -r line; do
    > [[ $line =~ $regex ]]
    > done < input
    $ printf '%s\n' "${BASH_REMATCH[@]}"
    one_two_three_fourpt1_fourpt2@fivept1_fivept2,six
    one
    two
    three
    fourpt1_fourpt2
    fivept1_fivept2
    six
    

    元素零 BASH_REMATCH 包含整个匹配项;其余元素从左侧包含单个捕获组。

    或者,您可以使用 read 先分开 @ ,然后再次使用 _ , 适当时。

    $ IFS="@" read -r first second <<< "$line"
    $ IFS=_ read -r f1 f2 f3 f4 <<< "$first"
    $ IFS=, read -r f5 f6 <<< "$second"
    

    因为第二个只读调用有4个参数, f4 将包含第3个 γ ,无需进一步的字段拆分 γ S.


    类似的正则表达式和两级拆分方案可以用在支持对文件内容进行更有效迭代的语言中(如Nahuel Fouilleul指出的那样)。 猛击 做得不太快。( 阅读 一个字节一个字节地读取其输入数据,而不是一次读取整个数据块,以避免读取多于一行输入数据所需的字节。)

        5
  •  0
  •   ctac_    6 年前

    如果您有一个带@的字段超过1次。 ……
    你可以试试这个锥子:

    echo "data1_data2@d_a_t_a_17,data3_data4@d_a_t_a_5,data6_data7" |
    awk '
    {
    i = split ( $0 , a , "_" )
    for ( j = 1 ; j <= i ; j++ )
      if ( a[j] !~ /@/ )
        print "d" ++k "==\"" a[j] "\""
      else
        {
          split ( a[j] , b , "@" )
          print "d" ++k "==\"" b[1] "\""
          sub ( ".*@" , "" , a[j] )
          while ( a[j] !~ "," )
            {
              c = c a[j] "_"
              j++
            }
            split ( a[j] , b , "," )
            c = c b[1]
            print "d" ++k "==\"" c "\""
            a[j] = b[2]
            j--
            c = ""
        }
    }'