[PYTHON] Ich habe ein Tool zum Generieren von Markdown aus der exportierten Scrapbox-JSON-Datei erstellt

Einführung

"Wie wäre es, wenn Sie fünf Jahre lang Ingenieur gewesen wären und keine Ausgabe produziert hätten?" Ich hatte das Gefühl einer Krise und beschloss, sie auf Qiita zu veröffentlichen. Es mag schwierig zu lesen sein, weil es der erste Artikel ist, aber bitte vergib mir.

Überblick

Ich habe mich entschieden, Scrapbox für interne Aktivitäten zu verwenden, aber schließlich wollte ich die Seiten in Scrapbox auf einem Dateiserver ablegen, damit ich sie als internes Asset belassen kann. Scrapbox hat eine Funktion zum Exportieren des Inhalts aller Seiten als JSON-Datei, ist jedoch schwer zu lesen. Also suchte ich nach einem Tool, das es in Markdown konvertieren und speichern konnte, aber ich konnte kein Tool finden, das gut aussah, also habe ich es selbst mit Python erstellt.

Die exportierte JSON-Datei hat dieses Format. (Export ohne Metadaten.)

john-project.json


{
  "name": "john-project",
  "displayName": "john-project",
  "exported": 1598595295,
  "pages": [
    {
      "title": "So verwenden Sie Scrapbox",
      "created": 1598594744,
      "updated": 1598594744,
      "id": "000000000000000000000000",
      "lines": [
        "So verwenden Sie Scrapbox",
        "Willkommen bei Scrapbox. Sie können diese Seite frei bearbeiten und verwenden.",
        "",
        "Laden Sie Mitglieder zu diesem Projekt ein",
        //Unterlassung
        " [Wir veröffentlichen Anwendungsfälle von Unternehmen https://scrapbox.io/case]",
        ""
      ]
    },
    {
      "title": "Die erste Zeile ist die Überschrift",
      "created": 1598594777,
      "updated": 1598595231,
      "id": "111111111111111111111111",
      "lines": [
        "Die erste Zeile ist die Überschrift",
        "[**Zwei Sternchen sind Überschriften]",
        "Aufzählungsliste mit Einzug",
        " \Wenn Sie die Anzahl von t erhöhen",
        " [[Fett gedruckt]]Oder[/ italic]、[-Stornierungslinie]Kann verwendet werden",
        " \Ich mag das nicht[-/* italic]Kann kombiniert werden",
        "[Seitenlink]Oder[Externer Link https://scrapbox.io]",
        "code:test.py",
        " for i in range(5):",
        "     print('[*Innerhalb von Codeblöcken ignorieren]')",
        "",
        "`[- code]`Ignorieren",
        "",
        "table:Tabellenformat",
        " aaa\tbbb\tccc",
        "ah ah\t\t Uuu",
        "\t111\t222\t333",
        ""
      ]
    }
  ]
}

Mit dem erstellten Tool wird es in die folgende Markdown-Datei konvertiert. (* Um das Erscheinungsbild von Qiita zu verbessern, gibt es einen Teil, in dem später dem Codeblock und dem Ende der Tabellenzeile ein Leerzeichen in voller Breite hinzugefügt wird.)

``Die erste Zeile ist die Überschrift.md`


#Die erste Zeile ist die Überschrift
###Zwei Sternchen sind Überschriften
-Aufzählungsliste mit Einzug
  -Wenn Sie die Anzahl erhöhen, werden die Zeichen weiter abgesenkt
- **Fett gedruckt**Oder_italic_ 、 ~~Stornierungslinie~~Kann verwendet werden
  -auf diese Weise_~~**italic**~~_Kann kombiniert werden
[Seitenlink]()Oder[ExternerLink](https://scrapbox.io)
code:test.py
``` 
 for i in range(5):
 print ('[* In Codeblöcken ignorieren]')
``` 

`[- code]`Ignorieren

table:Tabellenformat
|aaa|bbb|ccc| 
|-----|-----|-----|-----|
|ah ah||Uuu|
|111|222|333|


Das Erscheinungsbild wird wie folgt konvertiert. Die Zeilenumbrüche sind etwas locker, aber ziemlich leicht zu erkennen. Scrapbox_sample.png

最初の行は見出し.png

Politik

Viele Mitglieder (einschließlich meiner selbst) sind neu in Scrapbox, und es scheint, dass sie nicht sehr aufwändig sind. Daher habe ich beschlossen, nur die Notationen zu konvertieren, die ich verwenden konnte, ohne eine perfekte Konvertierung anzustreben. Die Konvertierungsmethode ist einfach. Verwenden Sie einfach reguläre Ausdrücke, um die in Scrapbox-Notation geschriebenen Teile zu finden und durch das Markdown-Format zu ersetzen. Führen Sie es schließlich aus, damit es von Personen verwendet werden kann, auf denen Python nicht installiert ist.

Umgebung

Ich habe Windows10 und Python3.7 verwendet.

Implementierung

Datei lesen

Stellen Sie sicher, dass Sie den JSON-Dateinamen als erstes Argument erhalten. Auf diese Weise können Sie es verwenden, indem Sie die JSON-Datei einfach auf die ausgeführte Datei ziehen und dort ablegen. Erstellen Sie außerdem einen Ordner für die Ausgabe von Markdown.

filename = sys.argv[1]
with open(filename, 'r', encoding='utf-8') as fr:
    sb = json.load(fr)
    outdir = 'markdown/'
    if not os.path.exists(outdir):
        os.mkdir(outdir)

Umwandlung

Von hier aus werden jede Seite und jede Zeile der Reihe nach konvertiert. Schreiben Sie das Conversion-Ziel in () jeder Überschrift.

Überschrift (erste Zeile)

Scrapbox interpretiert die erste Zeile als Überschrift. Fügen Sie daher am Anfang der ersten Zeile "#" (scharfes + halbes Feld) hinzu, um eine Überschrift zu erstellen.

for p in sb['pages']:
    title = p['title']
    lines = p['lines']
    is_in_codeblock = False
    with open(f'{outdir}{title}.md', 'w', encoding='utf-8') as fw:
        for i, l in enumerate(lines):
            if i == 0:
                l = '# ' + l

Codeblock (`` `Code: hoge.ext```)

In Scrapbox können Codeblöcke durch "code: hoge.ext" dargestellt werden. Solange der Zeilenanfang leer ist, wird der Codeblock fortgesetzt. Ich möchte nicht innerhalb des Codeblocks konvertieren, daher werde ich fortfahren und feststellen, ob sich die Zeile, die ich betrachte, innerhalb des Codeblocks befindet. Markdown-Notation beim Betreten und Verlassen eines Codeblocks```Hinzufügen.

# Codeblockverarbeitung
if l.startswith('code:'):
    is_in_codeblock = True
    l += f'\n```'
elif is_in_codeblock and not l.startswith(('\t', ' ', ' ')):
    is_in_codeblock = False
    fw.write('```\n')

# Unterlassung

# Konvertieren Sie, wenn kein Codeblock vorhanden ist
if not is_in_codeblock:
    l = convert(l)

####Tabelle(`table:hoge`

In der Scrapboxtable:hogeDie Tabelle kann mit ausgedrückt werden. Die Tabelle wird fortgesetzt, solange die Zeile mit einem Leerzeichen beginnt. Scrapbox-Tabellen haben keine Header, aber Markdown kann keine Tabellen ohne Header darstellen. Daher wird die erste Zeile als Header interpretiert. Die Zellen sind also durch Tabulatoren getrennt|Konvertieren zu. Leerzeichen am Anfang einer Zeile können Tabulatoren, Leerzeichen mit halber Breite und Leerzeichen mit voller Breite enthalten, sodass sie in Schlamm umgewandelt werden.

if l.startswith('table:'):
    is_in_table = True
elif is_in_table and not l.startswith(('\t', ' ', ' ')):
    is_in_table = False
if is_in_table:
    row += 1
    if row != 0:
         l = l.replace('\t', '|') + '|'
        if l.startswith(' '):
            l = l.replace(' ', '|', 1)
    if row == 1:
        col = l.count('|')
         l += f'\n{"|-----" * col}|'

####Code(`hoge`

Da ich den Code nicht konvertieren möchte, habe ich vor dem Konvertierungsprozess jeder Notation einen Prozess zum Löschen des Codeteils eingefügt. Es ist genauso geschrieben wie Markdown, sodass Sie es einfach löschen können.

def ignore_code(l: str) -> str:
    for m in re.finditer(r'`.+?`', l):
        l = l.replace(m.group(0), '')
    return l

####Hashtag(#hoge

Wenn dies am Anfang der Zeichenfolge geschrieben ist, kann es von Markdown als Überschrift interpretiert werden (es scheint je nach Viewer unterschiedlich auszusehen). aus diesem Grund,`Es wird als Code behandelt, indem es in eingeschlossen wird.

def escape_hash_tag(l: str) -> str:
    for m in re.finditer(r'#(.+?)[ \t]', ignore_code(l)):
        l = l.replace(m.group(0), '`' + m.group(0) + '`')
 if l.startswith ('#'): # 1 Zeile für alle Tags
        l = '`' + l + '`'
    return l

####Aufzählungszeichen (Einzug)

Die Anzahl der Einrückungen wird gezählt und durch das Markdown-Format ersetzt.

def convert_list(l: str) -> str:
    m = re.match(r'[ \t ]+', l)
    if m:
        l = l.replace(m.group(0),
                      (len(m.group(0)) - 1) * '  ' + '- ', 1)
    return l

####Fett gedruckt ([[hoge]][** hoge][*** hoge]

In der Scrapbox[[hoge]]Oder[* hoge]Wenn Sie möchten, wird es fett sein. Auch in letzterer Notation[** hoge]Wenn Sie das Sternchen wie in erhöhen, werden die Zeichen größer.

Von den letzteren Notationen wurden die Notationen mit zwei und drei Sternchen wie Markdown-Überschriften verwendet, daher habe ich sie entsprechend konvertiert. Davon abgesehen kann es gleichzeitig mit anderen Dekorationen verwendet werden, sodass es separat konvertiert wird.

def convert_bold(l: str) -> str:
    for m in re.finditer(r'\[\[(.+?)\]\]', ignore_code(l)):
        l = l.replace(m.group(0), '**' + m.group(1) + '**')
 m = re.match (r '\ [(\ * \ * | \ * \ * \ *) (. +?) \]', Igno_code (l)) # Wahrscheinlich die Überschrift
    if m:
        l = '#' * (5 - len(m.group(1))) + ' ' + \
 m.group (2) #Scrapbox hat mehr *
    return l

####Charakterdekoration ([* hoge][/ hoge][- hoge][-/* hoge]etc)

In Scrapbox zusätzlich zu fett, diagonal[/ hoge]Und Stornierungslinie[- hoge]Kann verwendet werden. Diese werden kombiniert[-/* hoge]Da es wie verwendet werden kann, verarbeitet es gleichzeitig.

def convert_decoration(l: str) -> str:
    for m in re.finditer(r'\[([-\*/]+) (.+?)\]', ignore_code(l)):
        deco_s, deco_e = ' ', ' '
        if '/' in m.group(0):
            deco_s += '_'
            deco_e = '_' + deco_e
        if '-' in m.group(0):
            deco_s += '~~'
            deco_e = '~~' + deco_e
        if '*' in m.group(0):
            deco_s += '**'
            deco_e = '**' + deco_e
        l = l.replace(m.group(0), deco_s + m.group(2) + deco_e)
    return l

(Das Highlight ist seltsam, aber ich konnte es nicht beheben)

####Verknüpfung([URL-Titel][Titel-URL][hoge]

In der Scrapbox[URL-Titel]Oder[Titel-URL]Drücken Sie den Link nach außen mit aus. Denken Sie nicht über die genaue Sache nachhttpIch habe beschlossen, diejenige, die mit beginnt, als URL zu interpretieren. Ebenfalls,[hoge]Ein solches Format ist ein Link zu einer anderen Seite in Scrapbox. Dieser Link kann nicht nach der Markdown-Ausgabe verwendet werden, sondern dahinter()Durch Hinzufügen wird nur das Erscheinungsbild wie ein Link.

def convert_link(l: str) -> str:
    for m in re.finditer(r'\[(.+?)\]', ignore_code(l)):
        tmp = m.group(1).split(' ')
        if len(tmp) == 2:
            if tmp[0].startswith('http'):
                link, title = tmp
            else:
                title, link = tmp
            l = l.replace(m.group(0), f'[{title}]({link})')
        else:
            l = l.replace(m.group(0), m.group(0) + '()')
    return l

###exe Umwandlung

Verwenden Sie zum Schluss pyinstaller zum Exe. Erstellen Sie eine Exe-Datei ohne Konsolenanzeige.

pip install pyinstaller
pyinstaller sb2md.py -wF

Ziehen Sie die JSON-Datei in die exe-Datei&Sie können das Programm ausführen, indem Sie es löschen.

##Schließlich

Der diesmal erstellte Code lautetGitHubEs wird in platziert. Wenn ich so einen kleinen Prozess schreibe, finde ich Python immer noch nützlich.

Ich habe neulich angefangen, Scrapbox zu verwenden, und ich bin jetzt nicht sehr gut darin, daher plane ich, es zu aktualisieren, sobald eine andere Verwendung herauskommt.

Recommended Posts

Ich habe ein Tool zum Generieren von Markdown aus der exportierten Scrapbox-JSON-Datei erstellt
Ich habe ein Tool erstellt, um automatisch ein einfaches ER-Diagramm aus der Anweisung CREATE TABLE zu generieren
Ich habe ein Plugin erstellt, um mit Vim eine Markdown-Tabelle aus CSV zu generieren
Ich habe einen Befehl zum Markieren des Tabellenclips gegeben
Ich habe ein Tool erstellt, um eine Wortwolke aus Wikipedia zu erstellen
Ich habe eine Untertiteldatei (SRT) aus JSON-Daten von AmiVoice erstellt
Ich habe ein Programm erstellt, um die Größe einer Datei mit Python zu überprüfen
So generieren Sie ein Python-Objekt aus JSON
Ich habe ein Tool erstellt, um Hy nativ zu kompilieren
Ich habe ein Tool erstellt, um neue Artikel zu erhalten
Ich habe ein Tool erstellt, um die Ausführungszeit von cron zu schätzen (+ PyPI-Debüt)
Ich habe ein Tool zum automatischen Sichern der Metadaten der Salesforce-Organisation erstellt
Ich habe ein Paket erstellt, um eine ausführbare Datei aus dem Hy-Quellcode zu erstellen
Ich möchte den Dateinamen von DataLoader sehen
Python-Skript, das eine JSON-Datei aus einer CSV-Datei erstellt
[Python] Ich habe ein System erstellt, um "das Rezept, das ich wirklich will" von der Rezeptseite einzuführen!
Ich habe eine Funktion erstellt, um das Modell von DCGAN zu überprüfen
[Titan Craft] Ich habe ein Werkzeug gemacht, um einen Riesen nach Minecraft zu rufen
Ich habe Sie dazu gebracht, Befehle über einen WEB-Browser auszuführen
Erstellt einen Toolsver, der Betriebssystem, Python, Module und Toolversionen an Markdown ausspuckt
Ich habe ein Skript in Python erstellt, um eine Textdatei für JSON zu konvertieren (für das vscode-Benutzer-Snippet).
Ich habe ein Tool erstellt, um die Antwortlinks von OpenAI Gym auf einmal zu erhalten
Ich habe versucht, ein Programm zu erstellen, um die Fehlersuche von Saiseriya zu lösen (Hinweis)
Ich habe versucht, ein Standbild aus dem Video auszuschneiden
Ich habe versucht, ein Gerüstwerkzeug für Python Web Framework Bottle zu erstellen
Ich habe den Befehl gegeben, einen farbenfrohen Kalender im Terminal anzuzeigen
Ich habe ein Tool zum automatischen Durchsuchen mehrerer Websites mit Selenium (Python) erstellt.
Ich möchte nur ein Signal vom Sub-Thread zum Haupt-Thread senden
[Django] Erstellt ein Feld zur Eingabe von Daten mit 4-stelligen Zahlen
Ich habe einen Küchentimer erstellt, der in der Statusleiste angezeigt wird!
Ich möchte die Einstellungsdatei erhalten und prüfen, ob die von jinja2 generierte JSON-Datei eine gültige JSON ist
Ich habe ein Skript in Python erstellt, um MDD-Dateien in das Scrapbox-Format zu konvertieren
Ich habe ein Skript erstellt, um Piktogramme anzuzeigen
Ich habe einen einfachen Timer erstellt, der vom Terminal aus gestartet werden kann
Ich habe eine Bibliothek konoha gemacht, die den Tokenizer auf ein schönes Gefühl umstellt
Ich habe ein Tool erstellt, um Jupyter py mit VS Code in ipynb zu konvertieren
Ich habe ein automatisches Stempelwerkzeug für den Browser erstellt.
Ich habe mit Python eine Einstellungsdatei erstellt
Ich habe eine Funktion erstellt, um die Bewegung eines zweidimensionalen Arrays (Python) zu sehen.
Ich habe ein Skript erstellt, um zu überprüfen, ob an der angegebenen Position der JSON-Datei in Python Englisch eingegeben wird.
[LINE Messaging API] Ich möchte eine Nachricht vom Programm an alle LINE senden
Ich habe eine Bibliothek zum Betreiben des AWS CloudFormation-Stacks über CUI (Python Fabric) erstellt.
Ich habe ein Tool erstellt, um Slack über Connpass-Ereignisse zu informieren, und es zu Terraform gemacht
Ich habe gerade ein Tool erstellt, mit dem Daten mithilfe der GUI-Operation einfach als Diagramm angezeigt werden können
Ich möchte gleichzeitig einen Musik-Player erstellen und Musik ablegen
Ich habe einen Appdo-Befehl erstellt, um Befehle im Kontext der App auszuführen
Ich habe versucht, automatisch eine Portverwaltungstabelle aus L2SW Config zu generieren
Ich konnte dem Futon nicht entkommen und baute eine vollautomatische Futon-Peeling-Maschine.
[Python] Ich habe versucht, den Typnamen als Zeichenfolge aus der Typfunktion abzurufen
Ich habe ein Programm erstellt, um Wörter im Fenster nachzuschlagen (vorherige Entwicklung)
Ich habe ein Skript erstellt, das das aktive Fenster mit win32gui von Python aufzeichnet
Ich habe ein nützliches Tool für Digital Ocean erstellt
So erstellen Sie eine JSON-Datei in Python
Ich habe ein Router-Konfigurationssammlungstool Config Collecor erstellt
Speichern Sie das Objekt in einer Datei mit pickle
Ich habe versucht, eine zufällige Zeichenfolge zu generieren
Ich möchte mit Python in eine Datei schreiben
Erstellt ein Tool zum Ausgeben eines Sequenzdiagramms aus einer Paketerfassungsdatei mit mehreren Knoten