vault backup: 2025-12-21 17:17:55
Some checks failed
Deploy Quartz site to GitHub Pages / build (push) Has been cancelled
Some checks failed
Deploy Quartz site to GitHub Pages / build (push) Has been cancelled
This commit is contained in:
120
content/z-Tech/tag_exam_questions.sh
Normal file
120
content/z-Tech/tag_exam_questions.sh
Normal file
@@ -0,0 +1,120 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Classify old exam question markdown files and update YAML tags with:
|
||||
# - exactly one of: anatomi | histologi
|
||||
# - optionally: öra | öga when confidently detected
|
||||
#
|
||||
# Writes an apply_patch patch to STDOUT.
|
||||
|
||||
shopt -s nullglob
|
||||
|
||||
is_numeric_md() {
|
||||
local base
|
||||
base=$(basename "$1")
|
||||
[[ $base =~ ^[0-9]+\.md$ ]]
|
||||
}
|
||||
|
||||
lower_body() {
|
||||
# Print lowercased body (after frontmatter) of a markdown file
|
||||
awk 'BEGIN{infront=0}
|
||||
/^---$/{c++; if(c==2){infront=0; next} if(c==1){infront=1; next}}
|
||||
{if(infront==0) print tolower($0)}' "$1"
|
||||
}
|
||||
|
||||
get_front_tags_line() {
|
||||
sed -n '1,12p' "$1" | awk -F': ' '/^tags:/ {print $2}'
|
||||
}
|
||||
|
||||
get_front_date_line() {
|
||||
sed -n '1,12p' "$1" | awk '/^date:/{print}'
|
||||
}
|
||||
|
||||
contains_re() {
|
||||
local content="$1" regex="$2"
|
||||
perl -0777 -ne "exit(!(/$regex/i))" <<< "$content"
|
||||
}
|
||||
|
||||
append_tag_if_missing() {
|
||||
local taglist="$1" tag="$2"
|
||||
# If tag not present as a distinct item, append before closing bracket
|
||||
if ! perl -e '$_=shift; $t=shift; exit(($_ =~ /(^|[,\[]\s*)\Q$t\E(,|\]|$)/) ? 0 : 1)' \
|
||||
-- "$taglist" "$tag"; then
|
||||
# Not present -> append
|
||||
if [[ "$taglist" =~ ^\[.*\]$ ]]; then
|
||||
# Ensure proper comma/space formatting
|
||||
if [[ "$taglist" == "[]" ]]; then
|
||||
taglist="[${tag}]"
|
||||
else
|
||||
if [[ "$taglist" == *"["*"," ]]; then
|
||||
taglist="${taglist%]} ${tag}]"
|
||||
else
|
||||
taglist="${taglist%]} , ${tag}]"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Fallback: create a list
|
||||
taglist="[${tag}]"
|
||||
fi
|
||||
fi
|
||||
printf '%s' "$taglist"
|
||||
}
|
||||
|
||||
classify_file() {
|
||||
local f="$1" body eye=0 ear=0 histo=0 unsure=0 anatomi=0
|
||||
body=$(lower_body "$f")
|
||||
|
||||
# Eye keywords
|
||||
if contains_re "$body" '\\b(retina|cornea|iris|pupill|lins|sclera|choroid|choroidea|ciliar|fovea|macula|syncentrum|n\\.?\\s*opticus|discus\\s+opticus|papilla\\s+opticus|glaskropp|konjunktiva|conjunctiva|muller|müller|tappar|stavar|zonula)\\b'; then eye=1; fi
|
||||
# Ear keywords
|
||||
if contains_re "$body" '\\b(öra|örat|öron|mellanörat|innerörat|trumhålan|hörsel|balans|vestibulo|cochle|scala|endolymf|perilymf|båggång|utrikel|saccul|otolit|stapes|malleus|incus|membrana\\s+tympani|auricul|tuba\\s+auditiva|hårcell|stria\\s+vascularis|corti|reissner|basilar)\\b'; then ear=1; fi
|
||||
# Histology keywords
|
||||
if contains_re "$body" '\\b(histologi|epitel|kubisk|cylindrisk|skivepitel|flerskiktat|bindväv|kollagen|vävnad|gliacell|astrocyt|oligodend|mikroglia|ependym|purkinje|granularis|molekularis|multiforme|pyramidalis|synaps|axon|dendrit|ganglie|ganglion|cellkärn|cellager|lamina)\\b'; then histo=1; fi
|
||||
|
||||
# Image-only uncertainty
|
||||
if contains_re "$body" '!\\[\\['; then
|
||||
if ! contains_re "$body" '\\b(thalamus|capsula|cortex|cerebell|nervus|putamen|lobus|ventrikel|pia|dura|arachnoid|ganglie|retina|cornea|iris|pupill|lins|sclera|ciliar|fovea|macula|opticus|cochle|scala|endolymf|perilymf|båggång|utrikel|saccul|otolit|stapes|malleus|incus)\\b'; then
|
||||
unsure=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if (( histo == 1 )); then anatomi=0; else anatomi=1; fi
|
||||
|
||||
echo "$eye $ear $histo $unsure $anatomi"
|
||||
}
|
||||
|
||||
generate_patch() {
|
||||
local root="Anatomi & Histologi 2/Gamla tentor" any_changes=0
|
||||
echo "*** Begin Patch"
|
||||
: > /tmp/unsure_files_list
|
||||
while IFS= read -r f; do
|
||||
is_numeric_md "$f" || continue
|
||||
read -r eye ear histo unsure anatomi < <(classify_file "$f")
|
||||
if (( unsure == 1 )); then
|
||||
echo "$f" >> /tmp/unsure_files_list
|
||||
continue
|
||||
fi
|
||||
oldtags=$(get_front_tags_line "$f")
|
||||
[[ -z "$oldtags" ]] && continue
|
||||
newtags="$oldtags"
|
||||
if (( anatomi == 1 )); then newtags=$(append_tag_if_missing "$newtags" "anatomi"); else newtags=$(append_tag_if_missing "$newtags" "histologi"); fi
|
||||
if (( ear == 1 )); then newtags=$(append_tag_if_missing "$newtags" "öra"); fi
|
||||
if (( eye == 1 )); then newtags=$(append_tag_if_missing "$newtags" "öga"); fi
|
||||
if [[ "$newtags" != "$oldtags" ]]; then
|
||||
dateline=$(get_front_date_line "$f")
|
||||
echo "*** Update File: $f"
|
||||
echo "@@"
|
||||
echo " ---"
|
||||
echo "-tags: $oldtags"
|
||||
echo "+tags: $newtags"
|
||||
echo " $dateline"
|
||||
echo " ---"
|
||||
any_changes=1
|
||||
fi
|
||||
done < <(find "$root" -type f -name "*.md" | sort)
|
||||
echo "*** End Patch"
|
||||
return $any_changes
|
||||
}
|
||||
|
||||
generate_patch
|
||||
|
||||
180
content/z-Tech/tag_exam_questions_v2.sh
Normal file
180
content/z-Tech/tag_exam_questions_v2.sh
Normal file
@@ -0,0 +1,180 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Classify old exam question markdown files and update YAML tags with:
|
||||
# - exactly one of: anatomi | histologi
|
||||
# - optionally: öra | öga when confidently detected
|
||||
#
|
||||
# Writes an apply_patch patch to STDOUT.
|
||||
|
||||
shopt -s nullglob
|
||||
shopt -s extglob
|
||||
|
||||
is_numeric_md() {
|
||||
local base
|
||||
base=$(basename "$1")
|
||||
[[ $base =~ ^[0-9]+\.md$ ]]
|
||||
}
|
||||
|
||||
lower_body() {
|
||||
# Print lowercased body (after frontmatter) of a markdown file
|
||||
awk 'BEGIN{infront=0}
|
||||
/^---$/{c++; if(c==2){infront=0; next} if(c==1){infront=1; next}}
|
||||
{if(infront==0) print tolower($0)}' "$1"
|
||||
}
|
||||
|
||||
get_front_tags_line() {
|
||||
sed -n '1,12p' "$1" | awk -F': ' '/^tags:/ {print $2}'
|
||||
}
|
||||
|
||||
get_front_date_line() {
|
||||
sed -n '1,12p' "$1" | awk '/^date:/{print}'
|
||||
}
|
||||
|
||||
contains_re() {
|
||||
local content="$1" regex="$2"
|
||||
# Use grep -E (ERE), case-insensitive
|
||||
echo "$content" | grep -Eiq -- "$regex"
|
||||
}
|
||||
|
||||
contains_lit() {
|
||||
local content="$1" needle="$2"
|
||||
grep -Fqi -- "$needle" <<< "$content"
|
||||
}
|
||||
|
||||
# Trim leading/trailing spaces
|
||||
trim() {
|
||||
local s="$1"
|
||||
s="${s##+([[:space:]])}"
|
||||
s="${s%%+([[:space:]])}"
|
||||
printf '%s' "$s"
|
||||
}
|
||||
|
||||
# Parse YAML inline list like "[a, b, c]" into global array TAGS
|
||||
parse_tags() {
|
||||
local list="$1" inner
|
||||
TAGS=()
|
||||
inner="$list"
|
||||
inner="${inner#'[']"; inner="${inner%']'}"
|
||||
IFS=',' read -r -a raw <<< "$inner"
|
||||
for tok in "${raw[@]}"; do
|
||||
# trim spaces
|
||||
t=$(echo "$tok" | sed -e 's/^\s\+//; s/\s\+$//')
|
||||
[[ -z "$t" ]] && continue
|
||||
# de-duplicate keeping order
|
||||
local found=0
|
||||
for ex in "${TAGS[@]}"; do [[ "$ex" == "$t" ]] && found=1 && break; done
|
||||
(( found == 0 )) && TAGS+=("$t")
|
||||
done
|
||||
}
|
||||
|
||||
has_tag() {
|
||||
local q="$1"
|
||||
for ex in "${TAGS[@]}"; do [[ "$ex" == "$q" ]] && return 0; done
|
||||
return 1
|
||||
}
|
||||
|
||||
add_tag_unique() {
|
||||
local q="$1"
|
||||
has_tag "$q" || TAGS+=("$q")
|
||||
}
|
||||
|
||||
remove_tag() {
|
||||
local q="$1" out=()
|
||||
for ex in "${TAGS[@]}"; do [[ "$ex" == "$q" ]] || out+=("$ex"); done
|
||||
TAGS=("${out[@]}")
|
||||
}
|
||||
|
||||
render_tags() {
|
||||
local out="["
|
||||
local first=1
|
||||
for ex in "${TAGS[@]}"; do
|
||||
if (( first )); then out+="$ex"; first=0; else out+=", $ex"; fi
|
||||
done
|
||||
out+="]"
|
||||
printf '%s' "$out"
|
||||
}
|
||||
|
||||
append_tag_if_missing() {
|
||||
local taglist="$1" tag="$2"
|
||||
if ! perl -e '$_=shift; $t=shift; exit(($_ =~ /(^|[,\[]\s*)\Q$t\E(,|\]|$)/) ? 0 : 1)' \
|
||||
-- "$taglist" "$tag"; then
|
||||
if [[ "$taglist" =~ ^\[(.*)\]$ ]]; then
|
||||
local inner
|
||||
inner=${BASH_REMATCH[1]}
|
||||
if [[ -z "$inner" ]]; then
|
||||
taglist="[${tag}]"
|
||||
else
|
||||
taglist="[${inner}, ${tag}]"
|
||||
fi
|
||||
else
|
||||
taglist="[${tag}]"
|
||||
fi
|
||||
fi
|
||||
printf '%s' "$taglist"
|
||||
}
|
||||
|
||||
classify_file() {
|
||||
local f="$1" body eye=0 ear=0 histo=0 unsure=0 anatomi=0
|
||||
body=$(lower_body "$f")
|
||||
|
||||
# Eye keywords
|
||||
if contains_re "$body" '(retina|cornea|iris|pupill|lins|sclera|choroid|choroidea|ciliar|fovea|macula|syncentrum|n\\.?[[:space:]]*opticus|discus[[:space:]]+opticus|papilla[[:space:]]+opticus|glaskropp|konjunktiva|conjunctiva|muller|müller|tappar|stavar|zonula)'; then eye=1; fi
|
||||
# Ear keywords
|
||||
if contains_re "$body" '(öra|örat|öron|mellanörat|innerörat|trumhålan|hörsel|balans|vestibulo|cochle|scala|endolymf|perilymf|båggång|utrikel|saccul|otolit|stapes|malleus|incus|membrana[[:space:]]+tympani|auricul|tuba[[:space:]]+auditiva|hårcell|stria[[:space:]]+vascularis|corti|reissner|basilar)'; then ear=1; fi
|
||||
# Histology keywords
|
||||
if contains_re "$body" '(histologi|epitel|kubisk|cylindrisk|skivepitel|flerskiktat|bindväv|kollagen|vävnad|gliacell|astrocyt|oligodend|mikroglia|ependym|purkinje|granularis|molekularis|multiforme|pyramidalis|synaps|axon|dendrit|ganglie|ganglion|cellkärn|cellager|lamina)'; then histo=1; fi
|
||||
|
||||
# Image-only uncertainty
|
||||
if contains_lit "$body" '![['; then
|
||||
if ! contains_re "$body" '(thalamus|capsula|cortex|cerebell|nervus|putamen|lobus|ventrikel|pia|dura|arachnoid|ganglie|retina|cornea|iris|pupill|lins|sclera|ciliar|fovea|macula|opticus|cochle|scala|endolymf|perilymf|båggång|utrikel|saccul|otolit|stapes|malleus|incus)'; then
|
||||
unsure=1
|
||||
fi
|
||||
fi
|
||||
|
||||
if (( histo == 1 )); then anatomi=0; else anatomi=1; fi
|
||||
|
||||
echo "$eye $ear $histo $unsure $anatomi"
|
||||
}
|
||||
|
||||
generate_patch() {
|
||||
local root="Anatomi & Histologi 2/Gamla tentor" any_changes=0
|
||||
echo "*** Begin Patch"
|
||||
: > /tmp/unsure_files_list
|
||||
while IFS= read -r f; do
|
||||
is_numeric_md "$f" || continue
|
||||
read -r eye ear histo unsure anatomi < <(classify_file "$f")
|
||||
if (( unsure == 1 )); then
|
||||
echo "$f" >> /tmp/unsure_files_list
|
||||
continue
|
||||
fi
|
||||
oldtags=$(get_front_tags_line "$f")
|
||||
[[ -z "$oldtags" ]] && continue
|
||||
parse_tags "$oldtags"
|
||||
# Ensure exactly one of anatomi|histologi
|
||||
if (( histo == 1 )); then
|
||||
remove_tag "anatomi"; add_tag_unique "histologi"
|
||||
else
|
||||
remove_tag "histologi"; add_tag_unique "anatomi"
|
||||
fi
|
||||
# Eye/Ear tags (add if detected)
|
||||
(( ear == 1 )) && add_tag_unique "öra"
|
||||
(( eye == 1 )) && add_tag_unique "öga"
|
||||
newtags=$(render_tags)
|
||||
if [[ "$newtags" != "$oldtags" ]]; then
|
||||
dateline=$(get_front_date_line "$f")
|
||||
echo "*** Update File: $f"
|
||||
echo "@@"
|
||||
echo " ---"
|
||||
echo "-tags: $oldtags"
|
||||
echo "+tags: $newtags"
|
||||
echo " $dateline"
|
||||
echo " ---"
|
||||
any_changes=1
|
||||
fi
|
||||
done < <(find "$root" -type f -name "*.md" | sort)
|
||||
echo "*** End Patch"
|
||||
return $any_changes
|
||||
}
|
||||
|
||||
generate_patch
|
||||
Reference in New Issue
Block a user