У меня есть некоторые данные TSV
ID Name Email
1 test test@email.com
321 stan stan@nowhere.net
Я хотел бы разобрать это в список хэшей
@entities[0]<Name> eq "test";
@entities[1]<Email> eq "stan@nowhere.net";
У меня возникли проблемы с использованием метасимвола новой строки для отделения строки заголовка от строки значения. Мое грамматическое определение:
use v6;
grammar Parser {
token TOP { <headerRow><valueRow>+ }
token headerRow { [\s*<header>]+\n }
token header { \S+ }
token valueRow { [\s*<value>]+\n? }
token value { \S+ }
}
my $dat = q:to/EOF/;
ID Name Email
1 test test@email.com
321 stan stan@nowhere.net
EOF
say Parser.parse($dat);
Но это возвращается Nil
. Я думаю, что я неправильно понимаю нечто фундаментальное в регулярных выражениях в raku.
Nil
, Это довольно бесплодно, что касается обратной связи, верно? Для отладки загрузите commaide, если вы еще этого не сделали, и / или посмотрите, как можно улучшить отчетность об ошибках в грамматиках? , Вы получили,Nil
потому что ваш шаблон принял семантику возврата. Смотрите мой ответ об этом. Я рекомендую вам отказаться от отслеживания. Смотрите ответ @ user0721090601 об этом. Для практичности и скорости, смотрите ответ JJ. Кроме того, вводный общий ответ на «Я хочу разобрать X с Раку. Кто-нибудь может помочь?» ,Ответы:
Вероятно, главное, что его отбрасывает, - это
\s
соответствие горизонтального и вертикального пространства. Чтобы соответствовать только горизонтального пространства, использования\h
и соответствовать только вертикальное пространство,\v
.Одна небольшая рекомендация, которую я хотел бы сделать, - избегать включения новых строк в токен. Вы также можете использовать операторы чередования
%
или%%
, поскольку они предназначены для работы с этим типом работы:Результатом
Parser.parse($dat)
этого является следующее:что показывает нам, что грамматика успешно все проанализировала. Однако давайте сосредоточимся на второй части вашего вопроса, которая заключается в том, что вы хотите, чтобы он был доступен в переменной для вас. Для этого вам нужно предоставить класс действий, который очень прост для этого проекта. Вы просто создаете класс, методы которого соответствуют методам вашей грамматики (хотя очень простые, такие как
value
/,header
которые не требуют специальной обработки помимо строкового преобразования, могут быть проигнорированы). Есть несколько более креативных / компактных способов обработки ваших, но я воспользуюсь довольно примитивным подходом для иллюстрации. Вот наш класс:Каждый метод имеет сигнатуру,
($/)
которая является переменной соответствия регулярного выражения. Итак, теперь давайте спросим, какую информацию мы хотим получить от каждого токена. В строке заголовка мы хотим, чтобы каждое из значений заголовка было в строке. Так:Любой маркер с квантором на нем будет рассматриваться как
Positional
, таким образом , мы могли бы также получить доступ к каждому отдельному матчу заголовка с$<header>[0]
,$<header>[1]
и т.д. Но теми объектами матча, так что мы просто быстро stringify их. Командаmake
позволяет другим токенам получать доступ к этим специальным данным, которые мы создали.Наша строка значений будет выглядеть одинаково, потому что
$<value>
токены - это то, что нас волнует.Когда мы доберемся до последнего метода, мы захотим создать массив с хешами.
Здесь вы можете увидеть, как мы получаем доступ к материалам, которые мы обработали,
headerRow()
иvalueRow()
: Вы используете.made
метод. Поскольку существует несколько valueRows, чтобы получить каждое из ихmade
значений, нам нужно составить карту (это ситуация, когда я обычно пишу свою грамматику просто<header><data>
в грамматике и определяю данные как несколько строк, но это достаточно просто это не так уж плохо).Теперь, когда у нас есть заголовки и строки в двух массивах, нужно просто сделать их массивом хэшей, что мы и делаем в
for
цикле. Ониflat @x Z @y
просто объединяют элементы, и присвоение хеша делает то, что мы имеем в виду, но есть и другие способы получить массив в нужном хеше.Как только вы закончите, вы просто
make
это, и тогда это будет доступно вmade
разборе:Это довольно часто, чтобы обернуть их в метод, как
Таким образом, вы можете просто сказать,
источник
class Actions { has @!header; method headerRow ($/) { @!header = @<header>.map(~*); make @!header.List; }; method valueRow ($/) {make (@!header Z=> @<value>.map: ~*).Map}; method TOP ($/) { make @<valueRow>.map(*.made).List }
Вы, конечно, должны сначала создать его экземпляр:actions(Actions.new)
.class Actions { has @!header; has %!entries … }
и просто бы значениеRow добавляло записи напрямую, чтобы вы в конечном итоге получили простоmethod TOP ($!) { make %!entries }
. Но это ведь Раку и TIMTOWTDI :-)<valueRow>+ %% \n
(захватывать строки, разделенные символами новой строки), но следуя этой логике,<.ws>* %% <header>
можно было бы «захватывать необязательно» пробел, который разделен не пробелами ". Я что-то пропустил?<.ws>
Не захватывает (<ws>
будет). ОП отметил, что формат TSV может начинаться с необязательного пробела. В действительности это, вероятно, было бы еще лучше определить с помощью токена между строками, определенного как\h*\n\h*
, который позволил бы определять valueRow более логично, как<header> % <.ws>
%
/%%
называл «чередование» оп ранее. Но это правильное имя. (В то время как использование этого для|
,||
и кузены всегда казались мне странными.) Я не думал об этой "обратной" технике раньше. Но это хорошая идиома для написания регулярных выражений, сопоставляющих повторяющийся шаблон с некоторым утверждением-разделителем не только между совпадениями шаблона, но и позволяющими его на обоих концах (используя%%
) или в начале, но не в конце (используя%
), как, э-э, альтернатива в конце, но не начало логикиrule
и:s
. Ницца. :)TL; DR: нет. Просто используйте
Text::CSV
, который способен справиться с любым форматом.Я покажу, сколько лет
Text::CSV
, вероятно, будет полезно:Ключевой частью здесь является обработка данных, которая преобразует исходный файл в массив или массивы (in
@data
). Однако это необходимо только потому, чтоcsv
команда не может иметь дело со строками; если данные в файле, вы можете пойти.Последняя строка напечатает:
Поле идентификатора станет ключом к хешу, а все это массив хешей.
источник
TL; DR
regex
s возврат.token
нет. Вот почему ваш шаблон не совпадает. Этот ответ сфокусирован на объяснении этого и на том, как легко исправить вашу грамматику. Однако вам, вероятно, следует переписать его или использовать существующий синтаксический анализатор, что вам определенно следует делать, если вы просто хотите анализировать TSV, а не узнавать о регулярных выражениях raku.Фундаментальное недоразумение?
(Если вы уже знаете, что термин "регулярные выражения" весьма неоднозначен, рассмотрите возможность пропуска этого раздела.)
Одна фундаментальная вещь, которую вы можете неправильно понять, это значение слова «регулярные выражения». Вот некоторые популярные значения, которые люди предполагают:
Формальные регулярные выражения.
Perl регулярные выражения
Совместимые с Perl регулярные выражения (PCRE).
Выражения соответствия шаблонам текста, называемые "регулярными выражениями", выглядят как любые из вышеперечисленных и выполняют нечто подобное.
Ни одно из этих значений не совместимо друг с другом.
Хотя регулярные выражения Perl семантически являются надмножеством формальных регулярных выражений, они гораздо более полезны во многих отношениях, но также более уязвимы для патологического возврата .
Хотя регулярные выражения, совместимые с Perl, совместимы с Perl в том смысле, что изначально они были такими же, как стандартные регулярные выражения Perl в конце 1990-х годов, и в том смысле, что Perl поддерживает подключаемые механизмы регулярных выражений, включая механизм PCRE, синтаксис регулярных выражений PCRE не идентичен стандартному. Регулярное выражение Perl используется по умолчанию Perl в 2020 году.
И хотя выражения сопоставления с текстовым шаблоном, называемые "регулярными выражениями", как правило, похожи друг на друга и сопоставляют весь текст, существуют десятки, а может быть, сотни вариантов синтаксиса и даже семантики для одного и того же синтаксиса.
Выражения соответствия шаблону текста Raku обычно называются либо «правилами», либо «регулярными выражениями». Использование термина «регулярные выражения» передает тот факт, что они похожи на другие регулярные выражения (хотя синтаксис был очищен). Термин «правила» передает тот факт, что они являются частью гораздо более широкого набора функций и инструментов, которые расширяются до синтаксического анализа (и далее).
Быстрое решение
С учетом вышеупомянутого фундаментального аспекта слова «регулярные выражения» я могу теперь обратиться к фундаментальному аспекту поведения вашего «регулярного выражения» .
Если мы переключим три шаблона в вашей грамматике для
token
декларатора наregex
декларатор, ваша грамматика будет работать так, как вы хотели:Единственное различие между a
token
и aregex
состоит в том, чтоregex
отступает, а atoken
нет. Таким образом:Во время обработки последнего шаблона (который может быть и часто называется «регулярное выражение», но фактическим декларатором которого
token
не являетсяregex
), он\S
будет проглатывать'b'
, как это было временно во время обработки регулярного выражения в предыдущей строке. Но поскольку шаблон объявлен как atoken
, механизм правил (иначе называемый «механизм регулярных выражений») не возвращается , поэтому общее сопоставление не выполняется.Вот что происходит в вашем ОП.
Правильное решение
Лучшее решение в целом отучить себя от предполагая обратного прослеживания поведения, потому что это может быть медленными и даже катастрофический медленно (неотличимо от программы повешения) при использовании в согласовании против злонамеренно построенной строки или один с случайно неудачной комбинацией символов.
Иногда
regex
с уместны. Например, если вы пишете одноразовый код, и регулярное выражение выполняет свою работу, то все готово. Хорошо. Это/ ... /
одна из причин того, что синтаксис в raku объявляет шаблон возврата, какregex
. (Опять же, вы можете написать,/ :r ... /
если хотите включить храповик - «храповик» означает противоположность «возврата», поэтому:r
переключает регулярное выражение вtoken
семантику.)Иногда обратное отслеживание все еще играет роль в контексте анализа. Например, в то время как грамматика для raku обычно избегает обратного отслеживания и вместо этого имеет сотни
rule
s иtoken
s, тем не менее, у нее все еще есть 3regex
s.Я проголосовал за ответ @ user0721090601 ++, потому что он полезен. Он также затрагивает несколько вещей, которые мне сразу показались нелогичными в вашем коде, и, что важно, прилипает к
token
s. Это может быть ответ, который вы предпочитаете, который будет крутым.источник