Как обрабатывать любой текстовый файл Unix/DOS/Mac в flex-сканере

Я хочу, чтобы мой гибкий сканер обрабатывал текстовые файлы с символами новой строки, закодированными с использованием lf (Unix), cr (Mac) или cr lf (DOS). Я не забочусь о поддержании точно точного количества строк.

Не делая ничего особенного в файле.l относительно конца строк и компиляции под Ubuntu, мой сканер работает как с файлами Unix, так и с файлами DOS. Тем не менее, файлы Mac делают его неудачным. Добавление правила для удаления любого несоответствующего символа (т. Е. Просто строки с символом .) не помогает Я считаю, что lex ищет \n для завершения строк и игнорирует \r в файлах DOS, но не работает в файлах Mac, потому что \n не появляется, поэтому он никогда не думает, что читает строку.

Должен быть простой способ справиться с этим! Кто-нибудь знает как?

1 ответ

(F) Лекс делает именно то, что вы просите. Если вам нужно распознать окончания строки и принять все три формы, вам нужно будет указать это, используя такой шаблон, как (\r\n?|\n),

(F) lex не является линейно-ориентированным, за исключением трех функций. Эти особенности предполагают, что строки заканчиваются \n, что верно как для текстовых файлов DOS и Unix. Если вы хотите работать с файлами Mac в старом стиле, вам нужно реализовать эти функции самостоятельно.

  1. Шаблоны начала строки (шаблоны, начинающиеся с ^). Вы можете использовать условия запуска (см. Ниже).

  2. Шаблоны конца строки (шаблоны, заканчивающиеся на $). $ может быть просто заменен завершающим контекстным оператором:

    (some_pattern)$
    

    (some_pattern)/(\r\n?|\n)

  3. Автоматический подсчет строк с использованием %option yylineno, (Только Flex) Вы не сможете рассчитывать автоматически; вам нужно сделать это вручную:

    (\r\n?|\n)    { ++yylineno; }
    

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

(F) lex позволяет сделать набор правил условным для состояния лексера, инкапсулированного в начальном состоянии. Например, если вам нужно сделать что-то другое для шаблона прямо в начале строки, вы можете выполнить переход к начальному условию начала строки в вашем шаблоне для новой строки:

%x LINE_START
%%
 /* ... */
\r\n?|\n    { ++yylineno; BEGIN(LINE_START); }
/* ... */
pattern                { /* pattern is not at the start of a line */ }
<LINE_START>pattern    { /* pattern is at the start of a line */
                         BEGIN(INITIAL);
                       }
<*>other-pattern       { /* might or might not be at the start of a line */
                         BEGIN(INITIAL); /* In case it wasn't */
                       }

Если вы столкнулись с какой-либо другой проблемой, вам следует подготовить соответствующий вопрос с подробным описанием проблемы и [mcse], в котором вы найдете проблему.

Другие вопросы по тегам