【问题标题】:How can I determine the ordinal position of a string inside a comma-delimited string?如何确定逗号分隔字符串中字符串的序号位置?
【发布时间】:2012-11-01 02:03:59
【问题描述】:

我目前正在编写一个重新排列 csv 文件内容的脚本。如果我有与此类似的行:

stack,over,flow,dot,com

我怎样才能确定字符串/单词在命令分隔字符串中的位置。因此,例如,如果我要搜索堆栈,它将返回数字 1,如果我要搜索流,则将返回数字 3,依此类推。我已经想到了几种方法可以做到这一点,但它们大多是冗长的脚本,所以我觉得可能有一种更短/更简单的方法来做到这一点。如果有人可以提供建议/帮助,我将不胜感激,谢谢。这也是在 bash 环境中执行的

【问题讨论】:

标签: linux bash csv


【解决方案1】:

awk oneliner:

awk -F, -vs=$search '{for (i=1;i<=NF;i++)if($i~"^"s"$"){print i;exit;}}{print "not found"}' yourString

(参见下面的示例测试)

kent$  l="stack,over,flow,dot,com"
kent$  echo $l
stack,over,flow,dot,com
kent$  search=over
kent$  echo $search
over    
kent$  awk -F, -vs=$search '{for (i=1;i<=NF;i++)if($i~"^"s"$"){print i;exit;}}{print "not found"}' <<<$l
2
kent$  search=foobar    
kent$  awk -F, -vs=$search '{for (i=1;i<=NF;i++)if($i~"^"s"$"){print i;exit;}}{print "not found"}' <<<$l 
not found

【讨论】:

    【解决方案2】:
    echo $line | awk -F, '{
      for(i=1;i<=NF;i++){
        if($i=="your_string") print i;
      }
    }'
    

    注意:NF 代表字段数。

    【讨论】:

      【解决方案3】:

      一个bash函数:

      position() {
          local search=$1
          local IFS=,
          local i=1
          set -- $2
          for word; do
              if [[ $word = $search ]]; then
                  echo $i
                  return
              fi
              ((i++))
          done
          echo -1
      }
      

      然后:

      $ position stack stack,over,flow,dot,com
      1
      $ position tack stack,over,flow,dot,com
      -1
      

      【讨论】:

        【解决方案4】:

        仅仅因为您要求 100% 的 bash 解决方案(这不使用 sed、awk、seq 等):

        L='stack,over,flow,dot,com'
        IFS=,
        set -- $L
        declare -A A
        for ((i=1; i<=$#; i++))
        do
            A[${!i}]=$i
        done
        
        # where's flow?
        echo "flow=${A[flow]}"
        

        【讨论】:

          【解决方案5】:

          您可以将逗号数到匹配的字符串:

          for word in stack over flow dot com ; do
              echo $word
              grep -o ".*$word" <<< stack,over,flow,dot,com \
              | grep -o , \
              | wc -l
          done
          

          但是,如果您想使用 CSV 进行更多操作,切换到 Perl 并使用 Text::CSV 将是可行的方法。

          【讨论】:

            【解决方案6】:

            分割行,然后找到行号

            你可以用sed分割行,然后找到匹配的行号。例如:

            search_term='flow'
            echo 'stack,over,flow,dot,com' |
                sed -e  's/,/\n/g' |
                sed -ne "/^${search_term}\$/ {=; q}"
            

            因为 sed 是面向行的,所以在搜索匹配的行号之前需要先转换整个文件。这就是为什么我们要通过管道传递到另一个 sed 实例,而不是简单地在当前进程中使用第二个表达式。

            当然还有其他方法可以做到这一点,但这更容易。 YMMV。

            【讨论】:

              【解决方案7】:

              sedgrep 代表到目前为止。这是awk 解决方案:

              echo "stack,over,flow,dot,com" | awk -F, '{ for (i=1; i < NF; ++i) if ($i == "flow") print i; }'
              

              【讨论】:

                【解决方案8】:

                假设您要查找所有个单词:

                $ LINE=stack,over,flow,dot,com
                $ read ${LINE//,/\ } rest < <(echo $(seq 100))
                $ echo $stack $over $flow $dot $com
                1 2 3 4 5
                

                当然,这很容易给您带来名称冲突,因此您可能需要在名称前加上前缀:

                $ LINE=stack,over,flow,dot,com
                $ read field_${v//,/\ field_} rest < <(echo $(seq 100))
                $ echo $field_stack $field_over $field_flow $field_dot $field_com
                1 2 3 4 5
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-05-19
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多