Parsing Russian Wiktionary content using XPath

As readers of this blog know, I’m an avid user of Anki to learn Russian. I have a number of sources for reference content that go onto my Anki cards. Notably, I use Wiktionary to get word definitions and the word with the proper syllabic stress marked. (This is an aid to pronunciation for Russian language learners.)

Since I’m lazy to the core, I came up with a system way of grabbing the stress-marked word from the Wiktionary page using lxml and XPath.

Being grateful for those who push our buttons


We need people to push our buttons, otherwise how are we to know what buttons we have?

Jetsunma Tenzin Palmo Ten Percent Happier podcast, February 8, 2021

Jetsunma Tenzin Palmo is a Buddhist nun interviewed on the excellent Ten Percent Happier podcast. It’s always possible to reframe situations where someone “pushes our buttons” to see it as an opportunity to better understand that there are these buttons, these sensitivities that otherwise evade our awareness.

Directly setting an Anki card's interval in the sqlite3 database

It’s always best to let Anki set intervals according to its view of your performance on testing. That said, there are times when directly altering the interval makes sense. For example, to build out a complete representation of the entire Russian National Corpus, I’m forced to enter vocabulary terms that should be obvious to even elementary Russian learners but which aren’t yet in my nearly 24,000 card database. Therefore, I’m entering these cards gradually. When they come up as new cards, I pass them as “Easy” on the first appearance, converting them to review cards. But ideally, I’d like to send them away for years.

Where the power lies in 2021

From an article recently on the BBC Russian Service:

Блокировка уходящего президента США в “Твиттере” и “Фейсбуке” привела к необычной ситуации: теоретически Трамп еще может начать ядерную войну, но не может написать твит.

“Blocking the outgoing U.S. President from Twitter and Facebook has led to an unusual situation: theoretically Trump can still start a nuclear war, but cannot write a Tweet.”

In only a week, he won’t be able to do either. But while celebrating the deplatforming of this vicious clown, I have a tinge of worry about why it means for the future of democracy. It nearly goes without saying that social networks have become nearly the de facto equals of representative government in the U.S.

More on integrating Hazel and DEVONthink

Since DEVONthink is my primary knowledge-management and repository tool on the macOS desktop, I constantly work with mechanisms for efficiently getting data into and out of it. I previously wrote about using Hazel and DEVONthink together. This post extends those ideas about and looks into options for preprocessing documents in Hazel before importing into DEVONthink as a way of sidestepping some of the limitations of Smart Rules in the latter. I’m going to work from a particular use-case to illustrate some of the options.

Undoing the Anki new card custom study limit

Recently I hit an extra digit when setting up a custom new card session and was stuck with hundreds of new cards to review. Desparate to fix this, I started poking around the Anki collection SQLite database, I found the collection data responsible for the extra cards. In the col table, find the newToday key and you’ll find the extra card count expressed as a negative integer. Just change that to zero and you’ll be good.

Copy Zettel as link in DEVONthink

Following up on my recent article on cleaning up Zettelkasten WikiLinks in DEVONthink, here’s another script to solve the problem of linking notes.

Backing up to the problem. In the Zettelkasten (or archive) - Zettel (or notes) are stored as list of Markdown files. But what happens when I want to add a link to another note into one that I’m writing? Since DEVONthink recognizes WikiLinks, I can just start typing but then I have to remember the exact date so that I can pick the item out of the contextual list that DEVONthink offers as links. Also, if I took that approach I would end up with the same problem of excessive text in the link that I would then have to clean up with the previous script.

Cleaning up Zettelkasten WikiLinks in DEVONthink Pro

Organizing and reorganizing knowledge is one my seemingly endless tasks. For years, I’ve used DEVONthink as my primary knowledge repository. Recently, though I began to lament the fact that while I seemed to be collecting and storing knowledge in a raw form in DEVONthink, that I wasn’t really processing and engaging with it intellectually.1 In other words, I found myself collecting content but not really synthesizing, personalizing and using it. While researching note-taking systems in the search for a better way to process and absord the information I had been collecting, I discovered the Zettelkasten method. I’m not going to go into it here because it has been exhaustively described elsewhere. But I’ll just say that:

Regex to match a cloze

Anki and some other platforms use a particular format to signify cloze deletions in flashcard text. It has a format like any of the following:

  • {{c1::dog::}}
  • {{c2::dog::domestic canine}}

Here’s a regular expression that matches the content of cloze deletions in an arbitrary string, keeping only the main clozed word (in this case dog.)

{{c\d::(.*?)(::[^:]+)?}}

To see it in action, here it is in action in a Python script:

import re

def stripCloze(searchText):
    return re.sub(r'{{c\d::(.*?)(::[^:]+)?}}', r"\1", searchText)

print(stripCloze("The {{c1::passengers::tourist riders}} spotted a breaching {{c2::whale}}."))

It should return The passengers spotted a breaching whale.

Removing stress marks from Russian text

Previously, I wrote about adding syllabic stress marks to Russian text. Here’s a method for doing the opposite - that is, removing such marks (ударение) from Russian text.

Although there may well be a more sophisticated approach, regex is well-suited to this task. The problem is that

def string_replace(dict,text):
   sorted_dict = {k: dict[k] for k in sorted(dict)}
   for n in sorted_dict.keys():
      text = text.replace(n,dict[n])
   return text

dict = { "а́" : "а", "е́" : "е", "о́" : "о", "у́" : "у",
      "я́" : "я", "ю́" : "ю", "ы́" : "ы", "и́" : "и",
      "ё́" : "ё", "А́" : "А", "Е́" : "Е", "О́" : "О",
      "У́" : "У", "Я́" : "Я", "Ю́" : "Ю", "Ы́" : "Ы",
      "И́" : "И", "Э́" : "Э", "э́" : "э"
   } 
   
print(string_replace(dict, "Существи́тельные в шве́дском обычно де́лятся на пять склоне́ний."))

This should print: Существительные в шведском обычно делятся на пять склонений.