Простенькая задачка с ну очень нетривиальным решением?

Аватар пользователя DRVTiny

Задача вроде бы проста до безобразия (но, оказывается, она совсем не так проста, как того хотелось бы ): на входе имеем строку, содержащую специальные теги вида ..., указывающие на то, что кусок строки, заключённый между тегами, представлен в кодировке BASE64 (6-ти битная). Нужно: выделить текст между тегами и переконвертить его в кодировку текущей установленной локали.
Вроде бы всё должно быть элементарно, но у меня не получается реализовать это на BASH!

Вот мой вариант парсера, обрабатывающего файл, состоящий из строк, содержащих теги ...:

#!/bin/bash
slf="${0##*/}"
file_tblAccounts="$1"
cmdBase64='/usr/local/bin/base64'
[ -f "${file_tblAccounts}" ] || { echo "$slf: Error: file ${file_tblAccounts} does not exist" >&2; exit 1; }
while read line; do
if echo "$line" | fgrep -q ''; then
( echo "$line" | sed 's%%[NEWLINE]\n
\n&%g' | \
while read subline; do
{ echo "$subline" | grep -q '^' && \
echo "$subline" | sed -r 's%%%g' | $cmdBase64 -d; } || echo "$subline"
done ) | tr '\n' ' ' | sed 's%\[NEWLINE\]%%g; s%
%%g; s%$%\n%'
else
echo "$line"
fi
done <"${file_tblAccounts}"

Здесь подстрока, заключенная между тегами, перекодируется утилитой base64. Если пара тегов (открывающий/закрывающий) всего одна, то вроде бы всё правильно работает нормально, но если таких пар хотя бы две, начинаются перекосы...

Аватар пользователя ks

Re: Простенькая задачка с ну очень нетривиальным решением?

Текст кода ломается форумом Грустный

Мой вариант

#!/bin/bash

slf="${0##*/}"
file_tblAccounts="$1"
cmdBase64='/usr/local/bin/base64'
[ -f "${file_tblAccounts}" ] || {
    echo "$slf: Error: file ${file_tblAccounts} does not exist" >&2
    exit 1
}

sed -r 's%%&\\n%g' ${file_tblAccounts} |
while read line; do
    case "$line" in
    *'')
        echo -n "$line" | sed 's%%%'
        while read line; do
            case "$line" in
            *'')
                echo -n "$line" | sed 's%%%'
                break
                ;;
            *)
                echo "$line"
                ;;
            esac
        done | $cmdBase64 -d
        ;;
    *)
        echo "$line"
        ;;
    esac
done

Аватар пользователя DRVTiny

Простенькая задачка с ну очень нетривиальным решением?

>Текст кода ломается форумом
Да, есть такое дело. Отсутпы в коде вообще удаляются напрочь, а символы экранирования (обратный слэш) вырезаются, если их не продублировать. В общем, здесь определённо не следует пользоваться BB-тегом code, иначе и правда казусов/досадных недоразумений не избежать.

ks, спасибо за ответ, Вы меня сподвигли наконец на то, чтобы пересмотреть свой подход к разбору тегов. Хотя я и не стал использовать Ваш FSA-подобный (FSA- это конечный автомат Улыбка) способ разбора, ограничившись нижеследующим простеньким и неустойчивым к ошибкам (например, если для закрывающего тега нет открывающего) кодом, всё равно идея была правильная: ни к чему плодить новые сущности (за искл. добавления одного-единственного спец-тега , без которого пробельные разделители после переноса строки не сохраняются) нужны лишние теги и совершенно ни к чему обособлять 'ки переводами строк со всех сторон...

Итак, вот собственно окончательный вариант кода:

#!/bin/bash
file_tblAccounts="$1"
while read lnFROMfile; do
echo "$lnFROMfile" | \
sed -r 's%%\n%g; s%%\n%g' | \
while read line; do
{ echo "$line" | fgrep -q '' && \
{ echo -n "$line" | sed -r 's%$%%' | base64 -d; echo -n ''; }; } || \
echo -n "$line"
done | \
sed -r 's%%%g; s%%%g'
done <"${file_tblAccounts}"

Отлично работает, между прочим! Улыбка

Аватар пользователя ks

Re: Простенькая задачка с ну очень нетривиальным решением?

Цитата:
Вы меня сподвигли

Рад стараться!

Цитата:
ни к чему плодить новые сущности (за искл. добавления одного-единственного спец-тега , без которого пробельные разделители после переноса строки не сохраняются

Да ну вас Улыбка Если настроить IFS, то не нужен

Цитата:
while read lnFROMfile; do
echo "$lnFROMfile" | \
sed -r 's%%\n%g; s%%\n%g' |

Зачем этот цикл?

Аватар пользователя DRVTiny

Re: Простенькая задачка с ну очень нетривиальным решением?

Цитата:
Если настроить IFS, то не нужен

А ведь и в самом деле... Если временно установить IFS равным чему-нибудь невразумительному, отличному от пробельного символа, то оболочка не будет самочинно обрезать пробелы по краям...

Цитата:
Зачем этот цикл?

Для того, чтобы построчно считывать файл. Если sed будет сразу читать весь файл, то на выходе станет невозможно отличить переводы строк, полученные после разбивки тегов от тех, которые собственно строки файла друг от друга отделяют.

RSS-материал