calc-fst

A demo implementation of the fuzzy string match described at https://github.com/patkaiist/calc-fst and https://calc.hypotheses.org/ for the journal Computer-Assisted Language Comparison in Practice

by patkaiist

HTML

<!-- A demo implementation of the fuzzy string match described at https://github.com/patkaiist/calc-fst and https://calc.hypotheses.org/ for the journal Computer-Assisted Language Comparison in Practice -->
<html>
  <style type="text/css">
    * {font-size: 16px; font-family: sans-serif}
  </style>
  <body>
    <p>
    Input a spelling using ny, ni, sh, ch, or ng to get a list of variant spellings.
    </p>
    <p>
      <input type="text" placeholder="nyou.pan" value="nyou.pan" id="input"/>
      <button onclick="show_variants()">
        get variants
      </button>
    </p>
    <p>
      <strong>all spelling variations:</strong> <span id="output"></span>
    </p>
  </body>
</html>

JavaScript

const replacements = {
    "ɲ": ["ny", "ni", "nyi"],
    "ŋ": ["ng", "ny"],
    "ʊ": ["ou","o","u"],
    "o": ["u"],
    "u": ["o"],
    "ʃ": ["si","sh","s"],
    "ʧ": ["ch", "chh", "j"]
};

function replaceWithFirst(variant) {
    for (const key in replacements) {
        const firstReplacement = replacements[key][0];
        variant = variant.split(key).join(firstReplacement);
    }
    return variant;
}

function generateVariations(input) {
    if (!input || input.length === 0) {
        return [""];
    }
    const segments = input.replace(/\./g, '.·').split('·');
    let variations = [''];
    for (const segment of segments) {
        const segmentVariations = [];
        for (const variation of variations) {
            const segmentVariants = generateSegmentVariations(segment);
            for (const segmentVariant of segmentVariants) {
                let variant = variation + segmentVariant;
                segmentVariations.push(replaceWithFirst(variant));
            }
        }
        variations = segmentVariations;
    }
    return variations
}

function generateSegmentVariations(segment) {
    let variations = [segment];
    for (const pattern in replacements) {
        let index = 0;
        while ((index = segment.indexOf(pattern, index)) !== -1) {
            for (const replacement of replacements[pattern]) {
                let variant = segment.slice(0, index) + replacement + segment.slice(index + pattern.length)
                variations.push(replaceWithFirst(variant));
            }
            index += 1;
        }
    }

    return variations;
}

function show_variants() {
	let term = document.getElementById("input").value
  term = term.replace(/'/g, "’").replace(/[^a-zA-Z'’.%]/g, "")
  let temp_term = term.replace(/ng|ny|ni|sh|si|ch|chh|j/g, function(match) {
      switch(match) {
          case 'chh':
          case 'ch':
          case 'j':
              return 'ʧ';
          case 'ng':
              return 'ŋ';
          case 'ny':
  ...