Skip to content

Instantly share code, notes, and snippets.

@sarsamurmu
Last active February 17, 2024 09:59
Show Gist options
  • Save sarsamurmu/77f9ab1c0fa8c7be0751ecd0c3009f24 to your computer and use it in GitHub Desktop.
Save sarsamurmu/77f9ab1c0fa8c7be0751ecd0c3009f24 to your computer and use it in GitHub Desktop.
Highlight partly matched word
<script>
{
let s = `{{Reading_Sentence}}`
const targets = `{{Morph}}`
/** Mark part for highlighting later */
const hl = (s, partial = false) => partial ? `{#(${s})}` : `{(${s})}`
s = s.replace(/\s+/g, ' ')
let output = null
targets.split(',').map(x => x.trim()).forEach((target) => {
if (s.includes(target)) {
// Has exact match
output = (output ?? s).replaceAll(target, hl(target))
} else {
/** @type {string} */
const inp = output ?? s
// Match part of words
let re = /[\[\]]/g
let m
const blindZones = []
while ((m = re.exec(inp)) != null) {
blindZones.push([m.index, re.exec(inp).index])
}
re = new RegExp(target[0], 'g')
let idx
while ((m = re.exec(inp)) != null) {
let inBlind = false
blindZones.forEach(([l, u]) => {
if (l < m.index && m.index < u) inBlind ||= true
})
if (!inBlind) {
idx = m.index
break
}
}
let i = 0
let offset = 0
let isSkip = false
let matchLength = 0
for (;;) {
const inpChar = inp[idx + i + offset]
if (inpChar === ' ') {
offset++
continue
}
if (inpChar === '[') {
isSkip = true
} else if (isSkip && inpChar === ']') {
isSkip = false
offset++
continue
}
if (isSkip) {
offset++
continue
}
// console.log(target[i], ' -- ', inpChar)
if (target[i] !== inp[idx + i + offset]) {
break
} else {
matchLength++
}
if (++i >= target.length) {
break
}
if (idx + i + offset >= inp.length) {
break
}
}
const endIdx = idx + i + offset
output = inp.substring(0, idx)
+ hl(inp.substring(idx, endIdx), matchLength !== target.length)
+ inp.substring(endIdx)
// console.log('Sub -', inp.substring(idx, idx+i+offset))
}
})
// Convert `{(a[b] cd e[f])}` --> `{(a[b])} {(cd)} {(e[f])}`
output = output.replace(/\{(#?)\((.*?)\)\}/g, (w, a, b) => {
return `{${a}(${b.replace(' ', `)} {${a}(`)})}`
})
output = output.replace(/\{#?\(\)\}/g, '')
if (/[\[\]]/.test(output) && 1) {
// Handle ruby
output = output.split(' ').map((w) => {
const rubyParts = w.split(/[\[\]]/)
let fin = ''
if (rubyParts)
for (let i = 0; i < rubyParts.length; i += 2) {
if (rubyParts[i + 1] != null) {
fin += `<ruby><rb>${rubyParts[i]}</rb><rt>${rubyParts[i + 1]}</rt></ruby>`
fin = fin.replace(/<ruby><rb>\{(#?)\((.*?)(?<!\)\})<\/rb>/, '{$1(<ruby><rb>$2</rb>')
} else {
fin += rubyParts[i]
}
}
return fin
}).join(' ')
}
// Highlight marked parts
output = output.replace(/\{\((.*?)\)\}/g, '<span style="color: #e48872">$1</span>')
// For partial matches
output = output.replace(/\{#\((.*?)\)\}/g, '<span style="color: #09a5ef">$1</span>')
document.querySelector('#SentenceColor .field').innerHTML = output
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment