Kabosu - Creando cosas

Logo de la página. Gato esférico con colores verdoso.

Trasteando con JMdict

Publicado: 2025-04-27

Etiquetas: Proyectos, Python


Buenos días, tardes o noches:

En este artículo voy a contar una idea que tuve que aprender vocabulario japonés, cómo la implementé con Python 3 y finalmente cómo la abandoné. Me ha salido bastante largo.

Ya he comentado alguna vez que sé algo de japonés. Aprendí lo básico por mi cuenta leyendo cosas en internet y luego en la universidad hice un par de cursos como asignaturas de libre elección. Ahí fue donde más aprendí y era capaz de leer textos sencillos. Durante la pandemia estuve recibiendo algunas clases online por videoconferencia pero no progresé demasiado. Desde que dejé las clases de vez en cuando repaso un poco los silabarios hiragana y katakana y los kanji más básicos. Gracias a eso puedo leer más o menos y moverme por los menús de los juegos japoneses. No necesito mucho más. De vocabulario y gramática prácticamente he perdido todos los conocimientos que tenía.

Para repasar japonés siempre uso la app de Android Obenkyo a la que voy a dedicar unos párrafos porque creo que se lo merece.

Obenkyo

Obenkyo es la mejor aplicación que conozco para estudiar japonés. Totalmente offline una vez la descargas. Tiene diccionarios de kanji, vocabulario, animaciones de cómo escribir los caracteres, un pequeño curso de japonés... Cualquier cosa que necesites si estás estudiando el idioma. Obenkyo es gratis con anuncios pero estos anuncios se pueden desactivar completamente pulsando un botón en el menú de opciones. Increíble.

Aunque Obenkyo no es una aplicación de código abierto sí que me parece un ejemplo de uso de conocimiento abierto y Creative Commons. Toda su utilidad la saca de combinar magistralmente montones de recursos de dominio público o licencia libre: KanjiVG para la información de los trazos de los kanji y animaciones, KANJIDIC para el diccionario de kanji, EDict y JFrench para el vocabulario, Tatoeba para mostrar frases de ejemplo del vocabulario y el curso de japonés de un tal Tae Kim. Por ejemplo, si pulsas en un kanji que has fallado en un ejercicio y te muestra significado, ejemplos de palabras que lo usan y cómo escribirlo combinando información de sus distintas fuentes de datos.

Captura de pantalla de Obenkyo mostrando el kanji 左

Como he dicho, es la mejor aplicación que conozco para estudiar japonés. Para aprender desde cero a lo mejor no es demasiado útil porque no es una aplicación como Duolingo que empieza poco a poco pero si vas a clase o estás estudiando por tu cuenta creo que es muy útil para buscar información de kanji y para repasarlos con los ejercicios que tiene.

He tenido Obenkyo instalada en todos mis teléfonos Android desde hace 10 o 15 años. La interfaz no ha cambiado nada desde entonces y sigue pareciendo una aplicación como las que había en las primeras versiones de Android pero realmente no necesita nada más. El único punto negativo es que no todo el material está traducido al español. Se obtiene mucha más información usando la aplicación en inglés. Creo que también tiene mucho contenido en francés ya que su autor habla ese idioma.

Hace una semanas me puse de nuevo a refrescar mis conocimientos. Obenkyo tiene ejercicios en los que te muestra un carácter y has de pulsar en su lectura o significado. Las típicas tarjetas que existen en muchas otras aplicaciones. Primero estuve repasando un poco cada día hiragana, luego katakana y finalmente los kanji más básicos. Suelo dejarlo cuando he memorizado los 100 o 150 kanji más básicos.

Captura de pantalla de Obenkyo mostrando un ejercicio de hiragana

Un paso más: vocabulario

Esta vez además de repasar que 左 significa izquierda me propuse aprender también cómo se lee cada kanji. Las lecturas de kanji son todo un mundo. Cada carácter tiene una más lecturas onyommi y kunyomi como se puede ver en la captura. Para memorizar las lecturas de cada kanji lo mejor es aprender vocabulario que las usen pero nunca me había puesto con eso porque no encontré un buen método para ello. Esta vez lo intenté con Obenkyo.

Cuando me salía un nuevo kanji en los ejercicios iba pulsando en cada carácter de la lista y leyendo su información básica. Como se ve a continuación, generalmente muestra el significado más básico del kanji, normalmente el kanji por sí solo, y seguidamente un montón de palabras mucho más complicadas que lo contienen.

Captura de pantalla de Obenkyo mostrando lecturas del kanji 左

En el caso concreto de 左, observé que aparecía la palabra 左右 que básicamente combina los kanji de "izquierda" y "derecha". Me pareció interesante averiguar si había otras palabras sencillas que se podían formar juntando los pocos kanji que ya sabía. Quizá por día usar esas palabras para aprender las lecturas de los kanji.

Lo primero que hice fue preguntar a los LLMs que tengo instalados localmente (Gemma y DeepSeek). Les pedí que me diesen palabras que estuvieran formadas solo por estos kanji: 人, 口, 木, 大, 手, 力, 一, 日, 本, 女. Fue inútil. Por más que lo intenté con distintos prompts siempre me soltaban palabras que usaban otros kanji más avanzados. Y no es que los LLMs locales son más pequeños y tontos. Probé también un par de veces con el modelo más grande de DeepSeek a través de su web y obtuve un resultado muy similar. En parte es entendible que fallen: estos modelos no funcionan con caracteres sino con tokens que son trozos de palabras por lo que tienen mucha dificultad para razonar sobre partes de palabras. Un LLM sabe qué tokens son más probables que aparezcan detrás de otro tokens pero no sabe casi nada sobre el contenido de los propios tokens.

Yo me lo guiso

Como normalmente ocurre, usar IA no fue la solución. La inspiración para este proyecto la encontré gracias a Obenkyo. Como he dicho, utiliza diversas fuentes de datos libres, de dominio público, Creative Commons, etc y tiene una sección en la que lista todo lo que usa e incluye enlaces a sus respectivas webs. Decidí que iba a crear un programa que usase esas mismas fuentes. Mi siguiente objetivo fue bajarme esos datos y hacer un script con el que obtener las palabras que me interesan.

Obenkyo usa KANJIDIC como base para sus listado de kanji. Por desgracia el enlace que hay en la aplicación no funcionaba pero no fue difícil encontrar el correcto. Y de todas formas tampoco me servía. KANJIDIC es un fichero XML que contiene un listado de miles de kanji con sus lecturas y significados pero no incluye vocabulario que es lo que me interesaba. Obenkyo obtiene sus palabras de EDICT aunque el proyecto parece llamarse hoy en día JMDict-EDICT. Este diccionario es un único fichero XML que contiene miles de palabras en japonés y sus traducciones a inglés y en algunos casos a otros idiomas como el español. El fichero descomprimido ocupa 113MB.

Me hice un parser cutre en Python para leer del XML todas las palabras:

import xml.etree.ElementTree as ET

def getLang(d):
    '''Extract the language attribute of a glosse.'''
    for k, v in d.items():
        if k.endswith('lang'):
            return v
    return 'eng'


def parse_jmdict(file_path):
    tree = ET.parse(file_path)
    root = tree.getroot()
    
    entries = []
   
    # For each entry in the dictionary
    for entry in root.findall('entry'):
        entry_data = {
            'id': entry.find('ent_seq').text if entry.find('ent_seq') is not None else None,
            'kanji': [],
            'readings': [],
            'meanings': []
        }
       
        # The word and its variations
        for k_ele in entry.findall('k_ele'):
            kanji = k_ele.find('keb').text if k_ele.find('keb') is not None else None
            if kanji:
                entry_data['kanji'].append(kanji)
        
        # Word in hiragana/katakana
        for r_ele in entry.findall('r_ele'):
            reading = r_ele.find('reb').text if r_ele.find('reb') is not None else None
            if reading:
                entry_data['readings'].append(reading)

        entry_data['entry'] = entry_data['kanji'] or entry_data['readings']
       
        # Extract meanings
        for sense in entry.findall('sense'):
            meaning = {
                'glosses': [gloss for gloss in sense.findall('gloss')],
            }

            # Keep only English and Spanish translations
            glosses = [(getLang(g.attrib), g.text) for g in meaning['glosses'] if getLang(g.attrib) in ['eng', 'spa']]
            meaning['glosses'] = glosses
            entry_data['meanings'].append(meaning)
        
        entries.append(entry_data)
    
    return entries

Mi portátil tarda casi medio minuto en cargar el diccionario con este código. Si quisiera usarlo para hacer serio debería convertir el XML a otro formato más eficiente.

Con las palabras y su significado ya podía buscar automáticamente palabras que estuvieran compuestas solo por los kanji que ya conozco.

kanji = list('人口木大手力一日本女')

lookup = set(kanji)
allow = set(katakana + hiragana)

def containsKanji(e, required, allowed):
    '''Checks if any of the variations of an entry is made up only of 'required' kanji and maybe uses 'allowed'.'''
    for x in e:
        foundRequired = False
        for c in x:
            if c in required:
                foundRequired = True
            elif c not in allowed:
                break

        else:
            if foundRequired:
                return True
    return False

for e in entries[10:]:
    entry = e['entry']
    if not containsKanji(entry, lookup, allow):
        continue

    print(e['entry'])
    print('\t', e['readings'])
    for m in e['meanings']:
        if m['glosses']:
            print('\t-', m['glosses'])

Cada entrada del diccionario tiene una o más formas. Por lo que he observado, una variante puede ser la misma palabra pero sustituyendo los kanji complicados por su lectura en hiragana. Por ejemplo 右肘 (codo derecho) tiene como variante 右ひじ en la que se mantiene el kanji 右 (derecha) pero se sustituye 肘 (codo) por su lectura. Esta explicación es necesaria para entender la función containsKanji. La función busca entre todas las variantes de una entrada si hay alguna que contiene al menos uno de los kanji de required y opcionalmente algún caracter de allowed. Esta última lista contiene los silabarios hiragana y katakana y la añadí para así obtener entradas que fueran kanji + kanas. Por ejemplo: 右クリックメニュー (menú contextual que sale al hacer click con el botón derecho del ratón).

Yo me lo como

Puse mi pequeña lista de kanji y me esperé un minuto. Obtuve 1075 entradas. Demasiadas.

Pongo aquí algunos 手本 (ejemplos):

Ejemplo:
['手本']
         ['てほん']
        - [('eng', 'model'), ('eng', '(good) example'), ('eng', 'exemplar'), ('eng', 'paragon')]
        - [('eng', 'model handwriting'), ('eng', 'model drawing'), ('eng', 'copybook')]
        - [('spa', 'modelo'), ('spa', 'muestra'), ('spa', 'ejemplo'), ('spa', 'catálogo')]

Un bocado:
['一口', 'ひと口']
         ['ひとくち']
        - [('eng', 'mouthful'), ('eng', 'morsel'), ('eng', 'bite')]
        - [('eng', 'gulp'), ('eng', 'sip'), ('eng', 'draft'), ('eng', 'draught')]
        - [('eng', 'one word'), ('eng', 'in short')]
        - [('eng', 'one share'), ('eng', 'one contribution')]
        - [('spa', 'bocado'), ('spa', 'una palabra'), ('spa', 'mordida'), ('spa', 'sorbo'), ('spa', 'trago')]
        - [('spa', 'una palabra')]


Cada día:
['一日一日']
         ['いちにちいちにち']
        - [('eng', 'gradually'), ('eng', 'day by day')]
        - [('eng', 'every day'), ('eng', 'each day')]
        - [('spa', 'gradualmente'), ('spa', 'día por día')]
        - [('spa', 'cada día')]

Un único talento
'一本やり', '一本槍']
         ['いっぽんやり']
        - [('eng', 'sticking to one thing (method, principle, objective, etc.)'), ('eng', 'never deviating from'), ('eng', 'persisting with
'), ('eng', 'focusing solely on'), ('eng', 'devotion to'), ('eng', 'single spear')]
        - [('eng', "one's sole talent"), ('eng', "one's only forte")]
        - [('spa', 'principio de guía'), ('spa', 'talento único de uno'), ('spa', 'unico talento propio'), ('spa', 'un principio de guía')]

Estuve ojeando la lista de palabras, la mayoría eran palabras con 一 bastante complicadas como la última que he puesto (un único talento) pero que una de sus variantes sustituía los kanji por hiragana y por eso mi filtro las seleccionó.

¿Y ahora qué?

Una vez hecho este experimento que me costó una o dos horas me doy cuenta de que su utilidad para el aprendizaje es más bien pobre. Con 10 kanji me salieron más de 1000 entradas del diccionario y yo calculo que sé unos 100 kanji en estos momentos. Si pusiera todos en la lista me saldrían varios miles de resutlados. Además muchas de las palabras eran expresiones complicadas o "avanzadas" que seguramente hay que usar en un determinado contexto y que no sirve de nada memorizarlas a lo bruto. Creo que esto ha sido otro ejemplo más de idea loca que tengo y que cuando la pruebo me doy cuenta de porqué nadie lo hace así. En general intentar "automatizar" o "optimizar" el aprendizaje de idiomas no parece ser buena idea. Mejor dejar a las personas que se dedican a la enseñanza.

No creo que lo haga por el momento pero quizá se podrían mejorar los resultados. Para cada entrada JMDict incluye el tipo de palabra (verbo, sustantivo, etc) quizá si centrase la búsqueda solo en sustantivos la lista tendría un poco más de utilidad. Y si el diccionario tuviera alguna indicación de la dificultad de la palabra (el nivel JLPT o similar) podría filtrar aún mejor los resultados.

Otra cosa que he sacado de este pequeño proyecto es que he conocido KANJIDIC y JMDict. Los tengo descargados y ahora cuando necesite hacer una búsqueda rápida de alguna palabra podré hacerlo offline.


Artículo siguiente: No Backup
Artículo anterior: Comentario sobre Video Game Backlog Zero