Bash text file editing/modifying

后端 未结 2 413
北海茫月
北海茫月 2021-01-27 18:52

I have a text file that I am trying to modify. I am taking the input file that has lines of the form of

(y+1/4,-x+1/2,z+3/4)

and trying to chan

相关标签:
2条回答
  • 2021-01-27 19:13
    #!/usr/bin/env bash
    
    filename="227.dat"
    
    re='[(]y[+]([[:digit:]/]+),-x[+]([[:digit:]/]+),z[+]([[:digit:]/]+)[)]';
    while IFS= read -r line; do
        if [[ $line =~ $re ]]; then
            printf '\t%s' \
                0 1 0 \
               -1 0 0 \
                0 0 1 \
                "${BASH_REMATCH[1]}" \
                "${BASH_REMATCH[2]}" \
                "${BASH_REMATCH[3]}";
            printf '\n';
        else
            echo "ERROR: $line does not match $re" 1>&2;
        fi;
    done <"$filename"
    

    ...given, your input, returns:

       0       1       0       -1      0       0       0       0       1       1/4     1/2     3/4
    

    ...which as far as I can tell is correct.


    A more complex approach, making unfounded extrapolations (given the lack of detail and exemplars in the question itself), might look like:

    #!/usr/bin/env bash
    while IFS='(),' read -a pieces; do
      declare -A vars=( [x]=1 [y]=1 [z]=1 [x_sigil]='' [y_sigil]='' [z_sigil]='' )
      for piece in "${pieces[@]}"; do
        #                1   2      3   4
        if [[ $piece =~ (-?)([xyz])([+]([[:digit:]/]+))? ]]; then
          if [[ ${BASH_REMATCH[4]} ]]; then                 # only if there *are* digits
            vars[${BASH_REMATCH[2]}]=${BASH_REMATCH[4]}     # ...then store them.
          fi
          vars[${BASH_REMATCH[2]}_sigil]=${BASH_REMATCH[1]} # store - if applicable
        fi
      done
      printf '\t%s' \
        "0"                 "${vars[x_sigil]}1" 0 \
        "${vars[y_sigil]}1" 0                   0 \
        0                   0                   "${vars[z_sigil]}1" \
        "${vars[y]}"        "${vars[x]}"        "${vars[z]}"
      printf '\n'
    done
    

    Given the sample inputs provided in a comment on this answer, output is:

    0   1   0   1   0   0   0   0   1   1   1   1
    0   1   0   1   0   0   0   0   1   1   1   1
    0   1   0   1   0   0   0   0   1   1   1   1
    0   1   0   1   0   0   0   0   -1  3/4 1/4 1/2
    0   1   0   -1  0   0   0   0   1   1/2 3/4 1/4
    0   -1  0   1   0   0   0   0   1   1/4 1/2 3/4
    0   -1  0   -1  0   0   0   0   -1  1   1   1
    0   -1  0   -1  0   0   0   0   -1  1   1   1
    0   -1  0   -1  0   0   0   0   -1  1   1   1
    0   -1  0   -1  0   0   0   0   1   1/4 3/4 1/2
    0   -1  0   1   0   0   0   0   -1  1/2 1/4 3/4
    0   1   0   -1  0   0   0   0   -1  3/4 1/2 1/4
    0   -1  0   -1  0   0   0   0   1   1/4 3/4 1/2
    0   -1  0   -1  0   0   0   0   1   1/4 3/4 1/2
    0   -1  0   -1  0   0   0   0   1   1/4 3/4 1/2
    0   -1  0   -1  0   0   0   0   -1  1   1   1
    0   -1  0   1   0   0   0   0   1   1/4 1/2 3/4
    0   1   0   -1  0   0   0   0   1   1/2 3/4 1/4
    0   1   0   1   0   0   0   0   -1  3/4 1/4 1/2
    0   1   0   1   0   0   0   0   -1  3/4 1/4 1/2
    0   1   0   1   0   0   0   0   -1  3/4 1/4 1/2
    0   1   0   1   0   0   0   0   1   1   1   1
    0   1   0   -1  0   0   0   0   -1  3/4 1/2 1/4
    0   -1  0   1   0   0   0   0   -1  1/2 1/4 3/4
    0   -1  0   1   0   0   0   0   -1  1/2 1/4 3/4
    0   -1  0   1   0   0   0   0   -1  1/2 1/4 3/4
    0   -1  0   1   0   0   0   0   -1  1/2 1/4 3/4
    0   -1  0   1   0   0   0   0   1   1/4 1/2 3/4
    
    0 讨论(0)
  • 2021-01-27 19:32

    Here's an approach that may simplify the parsing. Read each line into an array using IFS set to all possible delimiters and characters you don't care about:

    while IFS=$'\(\)+,' read -ra line; do
        for i in 1 3 5; do
            case "${line[$i]}" in
                x) printf "%s\t%s\t%s\t" 1 0 0 ;;
                y) printf "%s\t%s\t%s\t" 0 1 0 ;;
                z) printf "%s\t%s\t%s\t" 0 0 1 ;;
                -x) printf "%s\t%s\t%s\t" -1 0 0 ;;
                -y) printf "%s\t%s\t%s\t" 0 -1 0 ;;
                -z) printf "%s\t%s\t%s\t" 0 0 -1 ;;
            esac
        done
        for i in 2 4 6; do
            printf "%s\t" "${line[$i]}"
        done
        echo
    done < "$filename"
    
    0 讨论(0)
提交回复
热议问题