Jak zabrałbyś się do analizowania Markdown? [Zamknięte]


126

Edycja: Niedawno dowiedziałem się o projekcie o nazwie CommonMark, który poprawnie identyfikuje i radzi sobie z niejasnościami w oryginalnej specyfikacji Markdown. http://commonmark.org/ Ma świetną obsługę bibliotek C #.

Możesz znaleźć składnię tutaj .

Źródło, które następuje wraz z pobieraniem, jest napisane w Perlu , którego nie mam zamiaru szanować. Jest pełen wyrażeń regularnych i opiera się na skrótach MD5, aby uniknąć pewnych znaków. Coś w tym jest nie tak!

Mam zamiar na stałe zakodować parser dla Markdown . Jakie jest z tym doświadczenie?

Jeśli nie masz nic znaczącego do powiedzenia na temat faktycznego analizowania Markdown, oszczędź mi czasu. (Może to zabrzmieć ostro, ale tak, szukam wglądu, a nie rozwiązania, czyli biblioteki innej firmy).

Aby trochę pomóc w odpowiedziach, wyrażenia regularne mają na celu identyfikację wzorców ! NIE analizować całej gramatyki. To, co ludzie rozważają, to foobar.

  • Jeśli myślisz o Markdown, zasadniczo opiera się on na koncepcji akapitów.
  • W związku z tym rozsądnym podejściem może być podzielenie danych wejściowych na akapity.
  • Istnieje wiele rodzajów akapitów, na przykład nagłówek, tekst, lista, cytaty i kod.
  • Wyzwaniem jest zatem zidentyfikowanie tych akapitów i ich kontekstu.

Wrócę z rozwiązaniem, gdy uznam, że warto się nim podzielić.


2
@cletus pisze parser markdown, patrz cforcoding.com/search/label/markdown
Alex Angas,

Skończyło się na tym, że zrobiłem to samo. Jednak nie próbuję analizować przecen tak, jakby to była gramatyka formalna, ponieważ najwyraźniej tak nie jest. Zastosowałem różne wyrażenia regularne w sposób rekurencyjny. I w kilku przejściach. Udało się bardzo dobrze.
John Leidegren,

@JohnLeidegren, czy jest jakaś szansa, że ​​inni ciekawi użytkownicy, tacy jak ja, zobaczą twoją próbę przeanalizowania przecen?
jmlopez

@jmlopez Przepraszamy, nie mam już dostępu do tego źródła, jeśli potrzebujesz parsera przecen, jest dostępny pakiet NuGet, którego można użyć. Pomysł jest jednak dość prosty, po prostu zastosuj serię wyrażeń regularnych w przejściach, zacznij od podzielenia danych wejściowych na paragrafy, a następnie spróbuj określić, jakiego rodzaju jest to akapit, i tak dalej. Na koniec przeanalizuj linki i style znaków w samych akapitach.
John Leidegren

2
Powinieneś spojrzeć na Parsedown . Dzieli tekst na linie. Następnie sprawdza, jak te linie zaczynają się i odnoszą do siebie nawzajem.
Emanuil Rusev

Odpowiedzi:


69

Jedynym Przecena realizacja wiem, że wykorzystuje rzeczywiste parser, jest Jon MacFarleane „s peg-Przecena . Jego parser jest oparty na generatorze parsera Parsing Expression Grammar o nazwie peg .


EDYCJA: Mauricio Fernandez niedawno wydał swój parser Simple Markup Markdown , który napisał w ramach swojego silnika OcsiBlog Weblog Engine. Ponieważ parser jest napisany w OCaml , jest niezwykle prosty i krótki (268 SLOC dla parsera , 43 SLOC dla emitera HTML ), a jednocześnie niesamowicie szybki (20% szybszy niż dyskonto (napisany ręcznie zoptymalizowanym C) i sześćset razy szybszy niż BlueCloth ( Ruby)), mimo że nie jest jeszcze zoptymalizowany pod kątem wydajności. Ponieważ jest on przeznaczony tylko do użytku wewnętrznego przez samego Mauricio na jego blogu, istnieje kilka odchyleń od oficjalnej specyfikacji Markdown , ale Mauricio stworzył gałąź, która przywraca większość tych zmian .


1
ciekawy. być może spróbuję przekonwertować to na projekt f #
ShuggyCoUk,

@Benjol Ta sama stara historia: nie ma czasu: /
ShuggyCoUk

1
Terrence Parr (współautor ANTLR) napisał jeden dla ANTLR 4: github.com/parrt/mini-markdown
Chris S

17

W zeszłym tygodniu wypuściłem nową implementację języka Markdown Java opartą na parserze, nazwaną pegdown . pegdown używa parsera PEG, aby najpierw zbudować abstrakcyjne drzewo składni, które jest następnie zapisywane w HTML. Jako taka jest całkiem przejrzysta i dużo łatwiejsza do odczytania, utrzymania i rozszerzenia niż podejście oparte na wyrażeniach regularnych. Gramatyka PEG jest oparta na implementacji "peg-markdown" Johna MacFarlanesa C.

Może coś Cię zainteresuje ...


1
To jest teraz oficjalnie przestarzałe
Fabich

7

Gdybym miał spróbować przeanalizować markdown (i jego rozszerzenie Markdown extra ), myślę, że spróbuję użyć automatu stanowego i przeanalizować go po jednym znaku na raz, łącząc ze sobą niektóre wewnętrzne struktury reprezentujące fragmenty tekstu, gdy idę dalej, raz all jest analizowany, generując wynik z wszystkich obiektów połączonych ze sobą.

Zasadniczo, czytając plik wejściowy, budowałbym drzewo przypominające mini-DOM.
Aby wygenerować wynik, po prostu przeszedłbym przez drzewo i wyprowadził HTML lub cokolwiek innego (PS, LaTex, RTF, ...)

Rzeczy, które mogą zwiększyć złożoność:

  • Fakt, że możesz mieszać HTML i markdown, chociaż reguła może być łatwa do wdrożenia: po prostu zignoruj ​​wszystko, co znajduje się między dwoma zrównoważonymi tagami i wyślij to dosłownie.

  • Adresy URL i notatki mogą mieć swoje odniesienia na dole tekstu. Korzystanie ze struktur danych dla hiperłączy może po prostu zarejestrować coś takiego:

    [my text to a link][linkkey]
    results in a structure like: 
        URLStructure: 
        |  InnerText : "my text to a link"
        |  Key       : "linkkey"
        |  URL       : <null>
    
  • Nagłówki można zdefiniować za pomocą podkreślenia, co może zmusić nas do użycia prostej struktury danych dla ogólnego akapitu i zmodyfikowania jego właściwości w trakcie czytania pliku:

    ParagraphStructure:
    |  InnerText    : the current paragraph text 
    |                 (beginning of line until end of line).
    |  HeadingLevel : <null> or 1-4 when we can assess 
    |                 that paragraph heading level, if any.
    

W każdym razie, tylko kilka myśli.

Jestem pewien, że jest wiele drobnych szczegółów, którymi należy się zająć i jestem prawie pewien, że Regexes może się przydać podczas tego procesu.
W końcu mieli przetwarzać tekst.


3

Prawdopodobnie przeczytałbym specyfikację składni wystarczająco dużo razy, aby ją poznać i zorientować się, jak ją przeanalizować.

Czytanie istniejącego kodu parsera jest oczywiście genialne, zarówno po to, aby zobaczyć, co wydaje się być głównym źródłem złożoności, jak i jeśli zostaną użyte jakieś sprytne sztuczki. Użycie sum kontrolnych MD5 wydaje się nieco dziwne, ale nie przestudiowałem kodu wystarczająco, aby zrozumieć, dlaczego to się robi. Komentarz w procedurze zwanej _EscapeSpecialChars()stany:

Zastępujemy każdy taki znak odpowiadającą mu wartością sumy kontrolnej MD5; jest to prawdopodobnie przesada, ale powinno zapobiec przypadkowemu zderzeniu się z wartościami ucieczki.

Zastąpienie pojedynczego znaku pełnym MD5 wydaje się ekstrawaganckie, ale być może naprawdę ma sens.

Oczywiście mądrze byłoby rozważyć stworzenie „prawdziwej” składni dla narzędzia takiego jak Flex, aby wydostać się z bagna wyrażeń regularnych.


Ta sprawa z MD5 wciąż mnie niepokoi, również nadmierna manipulacja napisami musi być wolniejsza niż jakikolwiek przyzwoity parser, który możesz napisać sam.
John Leidegren,

2
Flex to tak naprawdę tylko połowa parsera; po tokenizacji danych wejściowych musisz ustalić, co oznaczają tokeny. Do tego służy generator parserów. Jest ich dużo. („Parser combinator”, „recursive-descent” i „LALR (1)” to słowa kluczowe dla Google.)
jrockway

1
@jrockway: to prawda, wydaje mi się, że wzruszyłem ramionami i pomyślałem „ale jeśli przeczyta Flex, automatycznie znajdzie Bizona”. :) Dzięki.
zrelaksuj się



1

Jeśli używasz języka programowania, który ma więcej niż trzech innych użytkowników, powinieneś być w stanie znaleźć bibliotekę do przeanalizowania go za Ciebie. Szybkie wyszukiwanie w Google ujawnia biblioteki CL, Haskell, Python, JavaScript, Ruby i tak dalej. Jest bardzo mało prawdopodobne, że będziesz musiał wymyślić to koło na nowo.

Jeśli naprawdę musisz napisać go od zera, polecam napisanie odpowiedniego parsera. Dzięki tej technice nie będziesz musiał uciekać przed rzeczami z hasłami MD5. (Zgadzam się, że jeśli musisz zrobić coś takiego, czas ponownie przemyśleć swój projekt).


Jestem gotów na wyzwanie. Patrzyłem na biblioteki, ale są po prostu okropne. Brzydki i głupi. Rozważam napisanie parsera w języku F #, ponieważ potrzebuję projektu w języku F #, ale prawdopodobnie w końcu zrobię to w C #.
John Leidegren

Miejmy nadzieję, że F # ma bibliotekę taką jak Parsec; jeśli tak, to będzie fajny projekt;)
jrockway

0

Istnieją biblioteki dostępne w wielu językach, w tym php, ruby, java, c #, javascript. Proponuję przyjrzeć się niektórym z nich w poszukiwaniu pomysłów.

Zależy to od tego, jakiego języka chcesz użyć, aby jak najlepiej go zaimplementować, będą istniały idiomatyczne i nieidiomatyczne sposoby na zrobienie tego.

Regeksy działają w perlu, ponieważ perl i regex są najlepszymi przyjaciółmi.


1
Regex i perl są najlepszymi przyjaciółmi, ponieważ ktoś tak powiedział. Nie ma więcej prawdy w tym fakcie niż jego historyczne pochodzenie, że był używany w ten sposób. Nie potrzebuję czegoś takiego jak perl.
John Leidegren,

7
Więc nie używaj tego ... Naucz się też ironii.
garrow

0

Markdown to JAWL (kolejny język wiki)

Istnieje wiele stron typu wiki typu open source, na których można sprawdzić kod parsera. Większość używa REGEX

Sprawdź wiki Screwturn, ma interesujący potok formatowania wieloprzebiegowego, bardzo fajną technikę - zobacz /core/Formatter.cs i /core/FormatterPipeline.cs

Najlepiej jest użyć / dołączyć do istniejącego projektu, tego typu rzeczy są zawsze o wiele trudniejsze, niż się wydaje


0

Tutaj możesz znaleźć implementację Markdown w JavaScript. Opiera się również w dużej mierze na wyrażeniach regularnych, ponieważ jest to najszybszy i najłatwiejszy sposób przeanalizowania tekstu.

Ale oszczędza część MD5.

Nie mogę pomóc bezpośrednio w kodowaniu parsowania, ale może ten link może ci pomóc w taki czy inny sposób.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.