2012-05-13 3 views
1

Я переместил этот вопрос code reviewБаша рекурсивных CSV парсер

Я написал метод рекурсивного спуска в Баше.

Мне интересно, можете ли вы указать мне что-то полезное. Он поддерживает обратные косые экраны и поля с кодами с отчетами об ошибках синтаксического анализа.

Сценарий работает как cut в некотором роде. Принимая входные данные из файла или stdin, позволяя пользователю выбирать, какую строку и какое поле они хотели бы распечатать. используя опции -l и -f соответственно. Список полей можно распечатать, а специальный разделитель для этого списка можно указать с помощью опций --list '1 2 3 4 5' и -list-seperator $ '\ n' например.

#!/bin/bash 

shopt -s extglob; # we need maxiumum expression capabilities enabled 

# option variables 
declare list='' delim=$'\n' field='' lineNum=1; 

while [[ ${1:0:1} = '-' ]]; do # Parse user arguments 

    case $1 in 
     -f) 
      field=$2; shift 2; 
     ;; 
     -l) 
      lineNum=$2; shift 2; 
     ;; 
     --list-seperator) 
      delim="$2"; shift 2; 
     ;; 
     --list) 
      list="$2"; shift 2; 
     ;; 
     *) break;; 
    esac 

done 

# open a user supplied file on stdin 
[[ -e "$1" ]] && exec 0<$1; 

# data from 'read/getline' 
declare input=''; 

# we are using sed to optimize input, the command just prints the desired line 
read -r input < <(sed -n ${lineNum}p) 
# why doesn't the above work as a pipe into read? 

# range of this line 
declare strLen=${#input} value=''; 

# data processing variables 
declare symbol='' value=''; 

# REGEX symbol "classes" 
declare nothing='' comma='[,]' quote='["]' backslash='[\]' text='[^,\"]'; 

# integers: 
declare -i iPos=-1 tPos=0; 

# output array: 
declare -a items=(); 

NextSymbol() { 

    symbol="${input:$((++iPos)):1}"; # get next char from string 

    ((iPos < strLen)); # return false if we are out of range 

} 

Accept() { 

    [[ -z "$symbol" && -z "$1" ]] && return 0; # accept "nothing/empty" 

    # if you can meld the above line into the next line 
    # let me know: [email protected]; this is some kind of bug! 
    # becare careful because expect expects 'nothing' to be empty. 
    # that's why it says 'end of input' 

    [[ "$symbol" =~ ^$1$ ]] && NextSymbol && return 0; # match symbol 
} 

Expect() { 
    Accept "$1" && return 
    local msg="$0: parse failure: line $lineNum: expected symbol: " 
    echo "$msg'${1:-end of input}'" >&2; 
    echo "$0: found: '$symbol'" >&2; 
    exit 1; 
} 

value() { 

    while Accept $text; do # symbol will not be what we expect here 
     value+=${input:$((iPos-1)):1}; # so get what we expect 
    done 

    Accept $nothing && { # this will only happen at end of the string 
     value+=${input:$((iPos-1)):1} # get the last char 
     pushValue; # push the data into the array 
    } 

} 

pushValue() { 
    items[tPos++]=$value; 
    value=''; # clear value! 
} 

quote() { 

    until [[ $symbol =~ $quote || -z $symbol ]]; do 
     value+=$symbol; 
     NextSymbol; 
    done 

    Expect $quote; 

} 

line() { 

    Accept $quote && { 
     quote 
     line; 
    } 

    Accept $backslash && { 
     value+=$symbol; 
     NextSymbol; 
     value; 
     line; 
    } 

    Accept $comma && { 
     pushValue; 
     line; 
    } 

    Accept $text && { 
     value=${input:$((iPos-1)):1}; 
     value; 
     line; 
    } 

} 

NextSymbol; 
    line; 
     Expect $nothing 


[[ $field ]] && { # want field  
    echo "${items[field-1]}" # print the item 
          # (index justified for human use) 
    exit; 
} 

[[ $list ]] && { # want list 
    for index in $list; do 
     echo -n "${items[index-1]}${delim}" # print the list 
              # (index justified for human use) 
    done 
    exit; 
} 

exit 1; # no field or list 
+0

Offtopic. Попробуйте http://codereview.stackexchange.com/ –

+0

@MarcB Вместо того, чтобы удалять, можем ли мы просто закрыть его и позволить мне оставить ссылку на codereview? –

+0

Я вижу много вопросов на боковой панели о скриптах и ​​CSV. Это будет полезно, даже если это «вне темы». –

ответ

2

Серьезно, способ сделать это быстрее - это написать на языке, который не интерпретируется.

Оболочка может быть плохим выбором для синтаксического анализатора по той же причине, что я бы не написал учетный пакет в ассемблере 6502 или в операционной системе COBOL.

И, честно говоря, awk не будет намного лучше. Он идеально подходит для последовательной обработки текста, но было бы просто применить его к чему-то сложному, как синтаксический анализатор.

Иногда вам просто нужно переосмыслить инструменты, которые вы используете. Если вы не можете это сделать, это скомпилированный язык, такой как C, по крайней мере, подумайте о языке, ориентированном на байт-код, например Python.

+0

уверен, но я не пытаюсь разбирать базу данных сервера terra USGS .. только некоторые небольшие скрипты bash. Скомпилированный, который я мог бы сделать в c или asm, и у меня есть на самом деле. Это для сценария проекта. К сожалению, awk или bash. –

+1

@ Тристон, мой совет все еще стоит. Если вы хотите скорость, интерпретируемые языки - не лучший способ. Или, смотря на это по-другому, если вы хотите создать хороший проект для оболочки, рекурсивные партизаны спуска, вероятно, не идеальная витрина. – paxdiablo

+0

У меня также есть компилятор AWK. Но, как я уже сказал, это просто сценарий. –

 Смежные вопросы

  • Нет связанных вопросов^_^