Anfuehrungszeichen: drei Loecher in meiner eigenen Wache
Die zweite Sitzung hat in den Praesentationen des Vaults 83 Stellen
gefunden — und damit auf Loecher in MEINER Wache gezeigt. Ich habe
sie nachgemessen, alle drei waren echt.
LOCH 1 — SIE SAH NUR `server/workspace-*.js`
Also ausgerechnet nicht `workspace.js`, die groesste Datei des
Hauses. Der weitere Filter fand dort sofort drei Stellen:
workspace.js:3404 Kanal „Chat-Moderation" (Protokoll)
workspace.js:3422 „${titel}" -> ${haus} (Protokoll)
workspace.js:3304 „${… || "ohne Titel"}" (siehe Loch 3)
Das ist heute der DRITTE Fall von „die Wache kennt nur die halbe
Menge" — nach pruef-struktur (sah nur die Pruefdateien, nicht die
Anwendung) und pruef-fingermass (sah keine variable Breite).
LOCH 2 — IHR AUSDRUCK GILT JE ZEILE
Ein `„`, das erst in der naechsten Zeile mit einem geraden `"`
schliesst, fiel durch. Gemessen: drei echte Faelle, zwei davon
sichtbarer Seitentext.
workspace/leistung.html „nicht / zugeordnet"
workspace/leistung.html „Backstage-Tabelle / einfuegen"
workspace/assets/js/ampel.js „noch ' + 'verbessern"
Beim letzten laeuft das Zitat ueber eine Zeichenketten-Verkettung.
Neue Regel ohne Fehlalarme: erst alle RICHTIG geschlossenen Paare
entfernen (auch mehrzeilig), dann die einzeilig falschen (die meldet
die alte Regel). Was danach noch ein `„` hat und binnen drei Zeilen
ein gerades `"`, ist ein Fund. Ausgenommen bleibt das Zeichen ALS
WERT — in `content: "„";` und in den Sprachtabellen ist das `„` der
Inhalt und das `"` die Begrenzung.
LOCH 3 — EINE AUSNAHME, DIE EINEN FUND VERSCHLUCKT HAT
Gefunden durch die ZAHL, nicht durch den Blick: Der weitere Filter
liess die Ausnahmen von 12 auf 13 steigen. Die dreizehnte war
`… „${zeile[titelSpalte] || "ohne Titel"}"`
Der Ausdruck blieb am `"` von `"ohne Titel"` haengen; als Inhalt kam
`${zeile[titelSpalte] || ` heraus, das endet auf ein Leerzeichen,
und damit galt „der Satz geht in der naechsten Zeile weiter". Das
echte Schlusszeichen stand hinter dem `}` und war gerade.
Dass die Ausnahmen gezaehlt UND genannt werden, hat ihn gefunden.
Genau dafuer steht die Zeile dort.
Behoben an der Wurzel: Anfuehrungszeichen innerhalb einer Einsetzung
`${…}` werden vorher durch X ersetzt, bei gleicher Laenge und
gleichen Zeilenumbruechen. Das nimmt einer ganzen Sorte
Fehlklassifizierung die Grundlage — die Ausnahmen fielen danach von
13 auf 11.
UND EIN VIERTES, BEIM MESSEN AUFGEFALLEN
`„Van-Van”` in assets/js/data-modis.js schliesst mit U+201D, dem
ENGLISCHEN Zeichen. Zweimal, beide Male in einer DEUTSCHEN Zeile
(`de:` und `"de-CH":`) — nicht einmal eine Uebersetzung, in der es
richtig waere. Eigene Regel dafuer, die keine Ausnahme braucht: Wer
mit `„` oeffnet, schliesst deutsch; in fremdsprachigen Zeilen steht
gar kein `„` am Anfang.
DIE AUSNAHMEZAHL IST JETZT STRENG. Sie stand auf „hoechstens 12" —
damit waere der Anstieg auf 13 nicht aufgefallen. Jetzt genau 11,
wie bei den Grundlinien in pruef-fingermass.
GEPRUEFT: pruef-struktur 68 -> 75 Pruefungen, 0 Fehler. Dazu
leistung-optik 59/0, ampel 47/0, treff 85/0, modi-verborgen 87/0 —
die Seiten, deren Text ich angefasst habe. Steuerzeichen: 830
Dateien, keines. Beide Stempel gesetzt.
Sechs echte Stellen berichtigt, vier neue Gegenproben.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+185
-3
@@ -806,6 +806,49 @@ console.log(`\n=== Das deutsche Schlusszeichen ===`);
|
||||
Datei sich beim naechsten Lauf selbst an. */
|
||||
const suche = new RegExp(AUF + '([^' + ZU + AUF + '"`\n]{1,140})"', "g");
|
||||
|
||||
/* ==== ANFUEHRUNGSZEICHEN IN EINER EINSETZUNG SIND KEINE ==========
|
||||
(01.10.2026, gefunden durch die ZAHL der Ausnahmen, nicht durch
|
||||
den Blick.)
|
||||
|
||||
Der weitere Filter liess die Ausnahmen von 12 auf 13 steigen.
|
||||
Die neue war server/workspace.js:3304 --
|
||||
|
||||
`… „${zeile[titelSpalte] || "ohne Titel"}"`
|
||||
|
||||
Das ist keine Ausnahme. Der Ausdruck blieb am `"` von
|
||||
`"ohne Titel"` haengen; als Inhalt kam `${zeile[titelSpalte] || `
|
||||
heraus, das endet auf ein Leerzeichen, und damit galt die Regel
|
||||
„der Satz geht in der naechsten Zeile weiter". Das ECHTE
|
||||
Schlusszeichen steht hinter dem `}` -- und war gerade. Die
|
||||
Ausnahme hat den Fund verschluckt.
|
||||
|
||||
Dass die Ausnahmen GEZAEHLT werden, hat ihn gefunden. Genau
|
||||
dafuer steht die Zeile dort.
|
||||
|
||||
Behoben an der Wurzel: Anfuehrungszeichen INNERHALB einer
|
||||
Einsetzung werden vorher durch X ersetzt. Laenge und
|
||||
Zeilenumbrueche bleiben gleich, alle Zeilennummern stimmen
|
||||
weiter. Aus
|
||||
|
||||
„${zeile[titelSpalte] || "ohne Titel"}"
|
||||
wird
|
||||
„${zeile[titelSpalte] || XohneX TitelX}"
|
||||
|
||||
und der Ausdruck findet das richtige Zeichen. Das nimmt einer
|
||||
ganzen Sorte Fehlklassifizierung die Grundlage, statt einen
|
||||
Einzelfall einzutragen. */
|
||||
const ohneEinsetzung = (text) => {
|
||||
let aus = "";
|
||||
let tief = 0;
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const c = text[i];
|
||||
if (c === "$" && text[i + 1] === "{") { tief++; aus += "${"; i++; continue; }
|
||||
if (c === "}" && tief > 0) { tief--; aus += "}"; continue; }
|
||||
aus += (tief > 0 && (c === '"' || c === "'" || c === "`")) ? "X" : c;
|
||||
}
|
||||
return aus;
|
||||
};
|
||||
|
||||
const warumNicht = (innen) => {
|
||||
if (/[<>=]/.test(innen)) return "HTML-Marke oder Attribut";
|
||||
if (innen.endsWith(" ")) return "Satz geht in der naechsten Zeile weiter";
|
||||
@@ -835,7 +878,11 @@ console.log(`\n=== Das deutsche Schlusszeichen ===`);
|
||||
...sammeln(join(SERVER, "..", "assets")),
|
||||
...readdirSync(join(SERVER, "..")).filter((n) => n.endsWith(".html"))
|
||||
.map((n) => join(SERVER, "..", n)),
|
||||
...readdirSync(SERVER).filter((n) => n.startsWith("workspace-") && n.endsWith(".js"))
|
||||
/* ALLE Servermodule, nicht nur `workspace-*` (01.10.2026).
|
||||
Gemessen war dieses Loch leer -- in den uebrigen Modulen stand
|
||||
keine falsche Stelle. Leer heisst aber nicht „kann nicht
|
||||
vorkommen", und der weitere Filter kostet nichts. */
|
||||
...readdirSync(SERVER).filter((n) => n.endsWith(".js"))
|
||||
.map((n) => join(SERVER, n)),
|
||||
];
|
||||
ok(dateien.length > 100, `${dateien.length} Dateien mit sichtbarem Text angesehen`);
|
||||
@@ -850,6 +897,7 @@ console.log(`\n=== Das deutsche Schlusszeichen ===`);
|
||||
if (art === ".js" || art === ".mjs") {
|
||||
text = text.replace(/^\s*\/\/.*$/gm, "");
|
||||
}
|
||||
text = ohneEinsetzung(text);
|
||||
/* Der Pfad AB DER WURZEL des Projekts -- ein abgeschnittener
|
||||
Pfad ist eine Meldung, der man nicht folgen kann. */
|
||||
const kurz = pfad.split(sep).join("/").split("/DogiHompage/").pop();
|
||||
@@ -870,9 +918,143 @@ console.log(`\n=== Das deutsche Schlusszeichen ===`);
|
||||
/* DIE AUSNAHMEN WERDEN GEZAEHLT UND GENANNT. Eine Ausnahme, die
|
||||
niemand sieht, waechst -- und irgendwann steht der echte Fall
|
||||
darin und faellt nicht mehr auf. */
|
||||
ok(stehenGelassen.length <= 12,
|
||||
/* DIE ZAHL MUSS GENAU STIMMEN, nicht „hoechstens" (01.10.2026).
|
||||
|
||||
Sie stand auf `<= 12`. Dann waere nicht aufgefallen, dass sie
|
||||
durch den weiteren Filter auf 13 gestiegen ist -- und die
|
||||
dreizehnte war gar keine Ausnahme, sondern ein verschluckter
|
||||
Fund (siehe `ohneEinsetzung` oben). Nach dessen Behebung sind
|
||||
es 11.
|
||||
|
||||
Waechst sie, ist eine neue Stelle dazugekommen, die die Regel
|
||||
nicht beurteilen kann. Sinkt sie, gehoert sie hier gesenkt --
|
||||
sonst deckt sie Platz fuer die naechste. Dieselbe Strenge wie
|
||||
bei den Grundlinien in pruef-fingermass. */
|
||||
const AUSNAHMEN = 11;
|
||||
ok(stehenGelassen.length === AUSNAHMEN,
|
||||
`${stehenGelassen.length} Stellen bleiben mit Grund stehen`
|
||||
+ ` (erlaubt: 12) — ${stehenGelassen.slice(0, 3).join(", ") || "—"}`);
|
||||
+ ` (unveraendert: ${AUSNAHMEN}) — ${stehenGelassen.slice(0, 3).join(", ") || "—"}`);
|
||||
|
||||
/* ==== UND UEBER DIE ZEILENGRENZE (01.10.2026) ====================
|
||||
|
||||
Angestossen von der zweiten Sitzung: Sie hat in den
|
||||
Praesentationen des Vaults 83 Stellen gefunden, weil sie
|
||||
ZEILENWEISE mitgezaehlt hat, wie viele `„` offen sind. Die Regel
|
||||
oben gilt je Zeile und kann das nicht.
|
||||
|
||||
Nachgemessen, was mir durchgegangen ist -- drei echte Faelle,
|
||||
zwei davon sichtbarer Seitentext:
|
||||
|
||||
workspace/leistung.html „nicht / zugeordnet"
|
||||
workspace/leistung.html „Backstage-Tabelle / einfuegen"
|
||||
workspace/assets/js/ampel.js „noch ' + 'verbessern"
|
||||
|
||||
Beim letzten laeuft das Zitat ueber eine
|
||||
Zeichenketten-Verkettung hinweg.
|
||||
|
||||
WIE ES GEHT, OHNE FEHLALARME: Erst alle RICHTIG geschlossenen
|
||||
Paare entfernen (auch mehrzeilig), dann die einzeilig falschen
|
||||
(die meldet die Regel oben, hier waeren sie doppelt). Was danach
|
||||
noch ein `„` hat und binnen drei Zeilen ein gerades `"`, ist ein
|
||||
Fund.
|
||||
|
||||
Ausgenommen bleibt dasselbe wie oben -- und zusaetzlich das
|
||||
Zeichen ALS WERT: In `content: "„";` und in den Sprachtabellen
|
||||
(`de: "„"`) ist das `„` der Inhalt und das `"` die Begrenzung. */
|
||||
const mehrzeilig = [];
|
||||
const alsWert = new RegExp('["\'`]\\s*' + AUF + '\\s*["\'`]');
|
||||
for (const pfad of dateien) {
|
||||
const art = pfad.slice(pfad.lastIndexOf("."));
|
||||
let text = readFileSync(pfad, "utf8")
|
||||
.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "))
|
||||
.replace(/<!--[\s\S]*?-->/g, (m) => m.replace(/[^\n]/g, " "));
|
||||
if (art === ".js" || art === ".mjs") text = text.replace(/^\s*\/\/.*$/gm, "");
|
||||
text = ohneEinsetzung(text);
|
||||
const kurz = pfad.split(sep).join("/").split("/DogiHompage/").pop();
|
||||
|
||||
/* Richtig geschlossene Paare weg -- auch ueber Zeilen. */
|
||||
let rest = text.replace(new RegExp(AUF + "[^" + ZU + AUF + "]{0,300}?" + ZU, "g"),
|
||||
(m) => m.replace(/[^\n]/g, " "));
|
||||
/* Und die einzeilig falschen -- die meldet die Regel oben. */
|
||||
rest = rest.replace(new RegExp(suche.source, "g"), (m) => m.replace(/[^\n]/g, " "));
|
||||
|
||||
const zeilen = rest.split("\n");
|
||||
for (const t of rest.matchAll(new RegExp(AUF, "g"))) {
|
||||
const zeile = rest.slice(0, t.index).split("\n").length;
|
||||
const fenster = zeilen.slice(zeile - 1, zeile + 3).join("\n");
|
||||
const paar = fenster.match(new RegExp(AUF + '([^' + ZU + AUF + ']{0,300}?)"'));
|
||||
if (!paar) continue;
|
||||
if (alsWert.test(zeilen[zeile - 1])) continue; /* Zeichen als Wert */
|
||||
if (/[<>=]/.test(paar[1]) || paar[1].includes("\\")) continue;
|
||||
mehrzeilig.push(`${kurz}:${zeile} ${AUF}${paar[1].replace(/\s+/g, " ").slice(0, 40)}"`);
|
||||
}
|
||||
}
|
||||
ok(mehrzeilig.length === 0,
|
||||
mehrzeilig.length
|
||||
? `ein deutsches Anfuehrungszeichen wird erst in einer SPAETEREN Zeile`
|
||||
+ ` mit einem geraden " geschlossen:\n ` + mehrzeilig.slice(0, 10).join("\n ")
|
||||
: "kein Anfuehrungszeichen wird ueber die Zeilengrenze hinweg falsch geschlossen");
|
||||
|
||||
/* ==== DAS ENGLISCHE SCHLUSSZEICHEN (01.10.2026) ==================
|
||||
|
||||
Deutsch oeffnet mit „ und schliesst mit “. Ein ” dahinter ist
|
||||
das ENGLISCHE Zeichen (U+201D). In data-modis.js stand zweimal
|
||||
`„Van-Van”`, beide Male in einer deutschen Zeile (`de:` und
|
||||
`"de-CH":`) -- also nicht einmal eine Uebersetzung, in der es
|
||||
richtig waere.
|
||||
|
||||
Wer mit „ oeffnet, schliesst deutsch. Deshalb braucht diese
|
||||
Regel keine Ausnahme fuer fremde Sprachen: Dort steht gar kein
|
||||
„ am Anfang. */
|
||||
const englisch = [];
|
||||
const EN_ZU = "\u201D";
|
||||
for (const pfad of dateien) {
|
||||
const text = readFileSync(pfad, "utf8")
|
||||
.replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " "))
|
||||
.replace(/<!--[\s\S]*?-->/g, (m) => m.replace(/[^\n]/g, " "));
|
||||
const kurz = pfad.split(sep).join("/").split("/DogiHompage/").pop();
|
||||
for (const t of text.matchAll(
|
||||
new RegExp(AUF + "([^" + ZU + AUF + EN_ZU + "\n]{1,160})" + EN_ZU, "g"))) {
|
||||
const zeile = text.slice(0, t.index).split("\n").length;
|
||||
englisch.push(`${kurz}:${zeile} ${AUF}${t[1].slice(0, 40)}${EN_ZU}`);
|
||||
}
|
||||
}
|
||||
ok(englisch.length === 0,
|
||||
englisch.length
|
||||
? `schliessen ein deutsches Anfuehrungszeichen mit dem ENGLISCHEN `
|
||||
+ `Zeichen (U+201D):\n ` + englisch.slice(0, 10).join("\n ")
|
||||
: "keines schliesst mit dem englischen Zeichen");
|
||||
|
||||
/* ---- GEGENPROBEN zu den zwei neuen Regeln --------------------- */
|
||||
{
|
||||
const ueberZeile = (code) => {
|
||||
let rest = code.replace(new RegExp(AUF + "[^" + ZU + AUF + "]{0,300}?" + ZU, "g"), " ");
|
||||
rest = rest.replace(new RegExp(suche.source, "g"), " ");
|
||||
const zl = rest.split("\n");
|
||||
let n = 0;
|
||||
for (const t of rest.matchAll(new RegExp(AUF, "g"))) {
|
||||
const z = rest.slice(0, t.index).split("\n").length;
|
||||
const f = zl.slice(z - 1, z + 3).join("\n");
|
||||
const paar = f.match(new RegExp(AUF + '([^' + ZU + AUF + ']{0,300}?)"'));
|
||||
if (!paar) continue;
|
||||
if (alsWert.test(zl[z - 1])) continue;
|
||||
if (/[<>=]/.test(paar[1]) || paar[1].includes("\\")) continue;
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
};
|
||||
ok(ueberZeile(`unter ${AUF}nicht\nzugeordnet" auf`) === 1,
|
||||
"Gegenprobe: ein Zitat ueber zwei Zeilen faellt auf");
|
||||
ok(ueberZeile(`unter ${AUF}nicht\nzugeordnet${ZU} auf`) === 0,
|
||||
" richtig geschlossen NICHT");
|
||||
ok(ueberZeile(`content: "${AUF}";`) === 0,
|
||||
" und das Zeichen als Wert auch nicht");
|
||||
const enTest = (code) => [...code.matchAll(
|
||||
new RegExp(AUF + "([^" + ZU + AUF + "\u201D\n]{1,160})\u201D", "g"))].length;
|
||||
ok(enTest(`${AUF}Van-Van\u201D`) === 1,
|
||||
"Gegenprobe: das englische Schlusszeichen faellt auf");
|
||||
ok(enTest(`${AUF}Van-Van${ZU}`) === 0, " das deutsche NICHT");
|
||||
}
|
||||
|
||||
/* ---- GEGENPROBEN ------------------------------------------------ */
|
||||
const findet = (code) => {
|
||||
|
||||
+3
-3
@@ -3301,7 +3301,7 @@ export function haeuserNachtragen(d) {
|
||||
unmittelbarere Beleg; erst wenn keiner etwas sagt, wird
|
||||
gefragt, woran die Zeile haengt. */
|
||||
const h = hausAus(leute(zeile)) || (ausEltern ? ausEltern(zeile) : null);
|
||||
const wer = `${tabelle}#${zeile.id} „${zeile[titelSpalte] || "ohne Titel"}"`;
|
||||
const wer = `${tabelle}#${zeile.id} „${zeile[titelSpalte] || "ohne Titel"}“`;
|
||||
if (h === "crew" || h === "agentur") { schreib.run(h, zeile.id); meldung.gesetzt++; }
|
||||
else if (h === "konflikt") meldung.konflikt.push(wer);
|
||||
else meldung.offen.push(wer);
|
||||
@@ -3401,7 +3401,7 @@ function restzeilenZuordnen(d, meldung) {
|
||||
.run(new Date().toISOString()).changes;
|
||||
d.prepare("UPDATE chat_raeume SET haus = 'crew' WHERE id = 3").run();
|
||||
meldung.gesetzt++;
|
||||
console.log(`[workspace] Kanal „Chat-Moderation" -> Team Dogi, ${n} aus dem anderen Haus herausgenommen.`);
|
||||
console.log(`[workspace] Kanal „Chat-Moderation“ -> Team Dogi, ${n} aus dem anderen Haus herausgenommen.`);
|
||||
}
|
||||
} catch (f) { console.error("[workspace] Kanal 3:", f?.message); }
|
||||
|
||||
@@ -3419,7 +3419,7 @@ function restzeilenZuordnen(d, meldung) {
|
||||
.run(haus, id, titel).changes;
|
||||
if (n) {
|
||||
meldung.gesetzt += n;
|
||||
console.log(`[workspace] Haus von Hand gesetzt: ${tabelle}#${id} „${titel}" -> ${haus}`);
|
||||
console.log(`[workspace] Haus von Hand gesetzt: ${tabelle}#${id} „${titel}“ -> ${haus}`);
|
||||
}
|
||||
} catch (f) {
|
||||
console.error(`[workspace] Restzeile ${tabelle}#${id}:`, f?.message);
|
||||
|
||||
Reference in New Issue
Block a user