Eine einfache Silbentrennung-Algorithmus (syllabicates spanische Wörter)
Silbentrennung
Manchmal müssen wir zum Anzeigen oder Drucken eines Textes und wir würden gerne lange Wörter getrennt, die am Ende einer Zeile nicht passen, damit sie nicht verfallen die nächste Zeile verlassen zuviel Speicherplatz ungenutzt.
Das Hauptproblem, das entsteht, ist wie ein Wort in Silben unterteilt. Nun, weiß ich wirklich nicht wie man syllabicate in Englisch, also lasse ich diesen Teil für Sie, aber ich hoffe, dass Sie das Beispiel auf Spanisch Syllabication nützlich finden:
procedure Syllabify(Syllables: TStringList; s: string);
const
Consonants = ['b','B','c','C','d','D','f','F','g','G',
'h','H','j','J','k','K','l','L','m','M','n','N',
'ñ','Ñ','p','P','q','Q','r','R','s','S','t','T',
'v','V','w','W','x','X','y','Y','z','Z'];
StrongVowels = ['a','A','á','Á','e','E','é','É',
'í','Í','o','ó','O','Ó','ú','Ú'];
WeakVowels = ['i','I','u','U','ü','Ü'];
Vowels = StrongVowels + WeakVowels;
Letters = Vowels + Consonants;
var
i, j, n, m, hyphen: integer;
begin
j := 2;
s := #0 + s + #0;
n := Length(s) - 1;
i := 2;
Syllables.Clear;
while i <= n do begin
hyphen := 0; // Do not hyphenate
if s[i] in Consonants then begin
if s[i+1] in Vowels then begin
if s[i-1] in Vowels then hyphen := 1;
end else if (s[i+1] in Consonants) and
(s[i-1] in Vowels) then begin
if s[i+1] in ['r','R'] then begin
if s[i] in ['b','B','c','C','d','D','f','F','g',
'G','k','K','p','P','r','R','t','T','v','V']
then hyphen := 1 else hyphen := 2;
end else if s[i+1] in ['l','L'] then begin
if s[i] in ['b','B','c','C','d','D','f','F','g',
'G','k','K','l','L','p','P','t','T','v','V']
then hyphen := 1 else hyphen := 2;
end else if s[i+1] in ['h', 'H'] then begin
if s[i] in ['c', 'C', 's', 'S', 'p', 'P']
then hyphen := 1 else hyphen := 2;
end else
hyphen := 2;
end;
end else if s[i] in StrongVowels then begin
if (s[i-1] in StrongVowels) then hyphen := 1
end else if s[i] = '-' then begin
Syllables.Add(Copy(s, j, i - j));
Syllables.Add('-');
inc(i);
j := i;
end;
if hyphen = 1 then begin // Hyphenate here
Syllables.Add(Copy(s, j, i - j));
j := i;
end else if hyphen = 2 then begin // Hyphenate after
inc(i);
Syllables.Add(Copy(s, j, i - j));
j := i;
end;
inc(i);
end;
m := Syllables.Count - 1;
if (j = n) and (m >= 0) and (s[n] in Consonants) then
Syllables[m] := Syllables[m] + s[n] // Last letter
else
Syllables.Add(Copy(s, j, n - j + 1)); // Last syllable
end;
Zum Testen der Prozedur können yon ein TextBox-Steuerelement und ein Etikett auf einem Blatt und in das Change-Ereignis des Textbox schreiben löschen:
procedure TForm1.Edit1Change(Sender: TObject);
var
Syllables: TStringList;
begin
Syllables := TStringList.Create;
try
Syllabify(Syllables, Edit1.Text);
Label1.Caption := StringReplace(Trim(Syllables.Text),
#13#10, '-', [rfReplaceAll]);
finally
Syllables.Free;
end;
end;
Jetzt haben wir ein Syllabication Verfahren, müssen wir feststellen, dass wir ein Wort in jeder Silbe Pause Silbentrennung kann nicht. Es ist in der Regel korrekt
und/oder beitreten kleine Silben auf der linken bzw. rechten Bildrand eines Wortes, z. B. garantieren, dass es mindestens zwei Silben auf beiden Seiten des Wortes wenn es getrennt wird, oder - wie in der folgenden Beispiel-um sicherzustellen, dass zumindest wir vier haben in beiden Seiten Zeichen wünschenswert:
procedure ApplyRules(Syllables: TStringList);
// Guarantee there are at least four letters in the left
// and right parts of the word
begin
with Syllables do begin
if Count = 1 then exit;
while Count > 1 do begin
if Length(Strings[0]) >= 4 then break;
Strings[0] := Strings[0] + Strings[1];
Delete(1);
end;
while Syllables.Count > 1 do begin
if Length(Strings[Count-1]) >= 4 then break;
Strings[Count-2] := Strings[Count-2]
+ Strings[Count-1];
Delete(Count-1);
end;
end;
end;
Schließlich kommt es die Zeit, analysieren den Text trennen die Zeilen eines Absatzes, die bestimmen, welche Wörter getrennt werden sollten. Das folgende Beispiel führt, die mit einem Text in einem Memo angezeigt werden:
procedure Hyphenate(Memo: TMemo; OriginalText: TStrings);
var
paragraph, i, j, k, m, n, MaxLineWidth: integer;
s, line: string;
Bitmap: TBitmap;
Canvas: TCanvas;
Syllables: TStringList;
begin
Syllables := TStringList.Create;
try
// We need a canvas to use its TextWidth method to get the width
// of the text to see if it fits in the client area or not. The
// TMemo class doesn't have a Canvas property, so we have to
// create one of our own.
Bitmap := TBitmap.Create;
Canvas := Bitmap.Canvas;
try
Canvas.Font := Memo.Font;
MaxLineWidth := Memo.ClientWidth - 6; // Maximum width
Memo.Lines.Clear;
for paragraph := 0 to OriginalText.Count - 1 do begin
// For each paragraph
s := OriginalText[paragraph]; // Get the original paragraph
// Get the lines in which we have to break the paragraph
while Canvas.TextWidth(s) > MaxLineWidth do begin
// First we find (in 'j') the index of the start of the
// first word that doesn't fit (the one to hyphenate)
j := 1;
n := Length(s);
i := 2;
while i <= n do begin
if (s[i-1] = ' ') and (s[i] <> ' ') then
j := i; // last beginning of a word
if Canvas.TextWidth(Copy(s, 1, i)) > MaxLineWidth then
break; // reached a width that doesn't fit
inc(i);
end;
// Where does the break occurs?
if s[i] = ' ' then begin
// Great! We break on a space
Memo.Lines.Add(Copy(s, 1, i - 1)); // Add the line
s := Copy(s, i + 1, n - i); // Remove the line
end else begin
// We break somewhere in a word. Now, we find (in 'k')
// the first space after the word (k)
k := j + 1;
while (k <= n) and (s[k] <> ' ') do inc(k);
// Divide the word in Syllables
Syllabify(Syllables, Copy(s, j, k - j));
ApplyRules(Syllables);
// Check (in 'm') how many syllables fit
m := 0;
Line := Copy(s, 1, j-1);
while Canvas.TextWidth(Line + Syllables[m] + '-')
<= MaxLineWidth do begin
Line := Line + Syllables[m];
inc(m);
end;
if (m <> 0) and (Syllables[m-1] <> '-') then begin
// Hyphenate
Line := Line + '-';
j := Length(Line);
if Syllables[m] = '-' then inc(j);
end;
Memo.Lines.Add(Line); // Add the line
s := Copy(s, j, n - j + 1); // Remove the line
end;
end;
Memo.Lines.Add(s); // Add the last line (it fits)
end;
finally
Bitmap.Free;
end;
finally
Syllables.Free;
end;
end;
Um die Prozedur zu testen, legen Sie eine Memo-Komponente ein Formular, richten Sie es zum Beispiel an die Spitze des Formulars (Align = AlTop) und schreiben Sie folgenden Code in das Resize-Ereignis des Formulars:
procedure TForm1.FormResize(Sender: TObject);
var
OriginalText: TStringList;
begin
OriginalText := TStringList.Create;
try
OriginalText.Add('Si se ha preguntado cómo hacen los '
+ 'programas procesamiento de textos para dividir palabras '
+ 'con de guiones al final de una línea, he aquí un '
+ 'ejemplo sencillo (en comparación con los que usan las '
+ 'aplicaciones de procesamiento de textos).');
OriginalText.Add('Este es un segundo párrafo que se provee '
+ 'con fines de ejemplo.');
Hyphenate(Memo1, OriginalText);
finally
OriginalText.Free;
end;
end;
Den vollständigen Quellcode dieses Artikels finden im Archiv Sie, die begleitenden Newsletter #23 Pascal
Silbentrennung
Silbentrennung : Mehreren tausend Tipps, um Ihr Leben einfacher machen.
Eine einfache Silbentrennung-Algorithmus (syllabicates spanische Wörter)
Silbentrennung
Manchmal müssen wir zum Anzeigen oder Drucken eines Textes und wir würden gerne lange Wörter getrennt, die am Ende einer Zeile nicht passen, damit sie nicht verfallen die nächste Zeile verlassen zuviel Speicherplatz ungenutzt.
Das Hauptproblem, das entsteht, ist wie ein Wort in Silben unterteilt. Nun, weiß ich wirklich nicht wie man syllabicate in Englisch, also lasse ich diesen Teil für Sie, aber ich hoffe, dass Sie das Beispiel auf Spanisch Syllabication nützlich finden:
procedure Syllabify(Syllables: TStringList; s: string);
const
Consonants = ['b','B','c','C','d','D','f','F','g','G',
'h','H','j','J','k','K','l','L','m','M','n','N',
'ñ','Ñ','p','P','q','Q','r','R','s','S','t','T',
'v','V','w','W','x','X','y','Y','z','Z'];
StrongVowels = ['a','A','a','A','e','E','e','E',
'i','I','o','o','O','O','u','U'];
WeakVowels = ['i','I','u','U','ü','Ü'];
Vowels = StrongVowels + WeakVowels;
Letters = Vowels + Consonants;
var
i, j, n, m, hyphen: integer;
begin
j := 2;
s := #0 + s + #0;
n := Length(s) - 1;
i := 2;
Syllables.Clear;
while i <= n do begin
hyphen := 0; // Do not hyphenate
if s[i] in Consonants then begin
if s[i+1] in Vowels then begin
if s[i-1] in Vowels then hyphen := 1;
end else if (s[i+1] in Consonants) and
(s[i-1] in Vowels) then begin
if s[i+1] in ['r','R'] then begin
if s[i] in ['b','B','c','C','d','D','f','F','g',
'G','k','K','p','P','r','R','t','T','v','V']
then hyphen := 1 else hyphen := 2;
end else if s[i+1] in ['l','L'] then begin
if s[i] in ['b','B','c','C','d','D','f','F','g',
'G','k','K','l','L','p','P','t','T','v','V']
then hyphen := 1 else hyphen := 2;
end else if s[i+1] in ['h', 'H'] then begin
if s[i] in ['c', 'C', 's', 'S', 'p', 'P']
then hyphen := 1 else hyphen := 2;
end else
hyphen := 2;
end;
end else if s[i] in StrongVowels then begin
if (s[i-1] in StrongVowels) then hyphen := 1
end else if s[i] = '-' then begin
Syllables.Add(Copy(s, j, i - j));
Syllables.Add('-');
inc(i);
j := i;
end;
if hyphen = 1 then begin // Hyphenate here
Syllables.Add(Copy(s, j, i - j));
j := i;
end else if hyphen = 2 then begin // Hyphenate after
inc(i);
Syllables.Add(Copy(s, j, i - j));
j := i;
end;
inc(i);
end;
m := Syllables.Count - 1;
if (j = n) and (m >= 0) and (s[n] in Consonants) then
Syllables[m] := Syllables[m] + s[n] // Last letter
else
Syllables.Add(Copy(s, j, n - j + 1)); // Last syllable
end;
Zum Testen der Prozedur können yon ein TextBox-Steuerelement und ein Etikett auf einem Blatt und in das Change-Ereignis des Textbox schreiben löschen:
procedure TForm1.Edit1Change(Sender: TObject);
var
Syllables: TStringList;
begin
Syllables := TStringList.Create;
try
Syllabify(Syllables, Edit1.Text);
Label1.Caption := StringReplace(Trim(Syllables.Text),
#13#10, '-', [rfReplaceAll]);
finally
Syllables.Free;
end;
end;
Jetzt haben wir ein Syllabication Verfahren, müssen wir feststellen, dass wir ein Wort in jeder Silbe Pause Silbentrennung kann nicht. Es ist in der Regel korrekt
und/oder beitreten kleine Silben auf der linken bzw. rechten Bildrand eines Wortes, z. B. garantieren, dass es mindestens zwei Silben auf beiden Seiten des Wortes wenn es getrennt wird, oder - wie in der folgenden Beispiel-um sicherzustellen, dass zumindest wir vier haben in beiden Seiten Zeichen wünschenswert:
procedure ApplyRules(Syllables: TStringList);
// Guarantee there are at least four letters in the left
// and right parts of the word
begin
with Syllables do begin
if Count = 1 then exit;
while Count > 1 do begin
if Length(Strings[0]) >= 4 then break;
Strings[0] := Strings[0] + Strings[1];
Delete(1);
end;
while Syllables.Count > 1 do begin
if Length(Strings[Count-1]) >= 4 then break;
Strings[Count-2] := Strings[Count-2]
+ Strings[Count-1];
Delete(Count-1);
end;
end;
end;
Schließlich kommt es die Zeit, analysieren den Text trennen die Zeilen eines Absatzes, die bestimmen, welche Wörter getrennt werden sollten. Das folgende Beispiel führt, die mit einem Text in einem Memo angezeigt werden:
procedure Hyphenate(Memo: TMemo; OriginalText: TStrings);
var
paragraph, i, j, k, m, n, MaxLineWidth: integer;
s, line: string;
Bitmap: TBitmap;
Canvas: TCanvas;
Syllables: TStringList;
begin
Syllables := TStringList.Create;
try
// We need a canvas to use its TextWidth method to get the width
// of the text to see if it fits in the client area or not. The
// TMemo class doesn't have a Canvas property, so we have to
// create one of our own.
Bitmap := TBitmap.Create;
Canvas := Bitmap.Canvas;
try
Canvas.Font := Memo.Font;
MaxLineWidth := Memo.ClientWidth - 6; // Maximum width
Memo.Lines.Clear;
for paragraph := 0 to OriginalText.Count - 1 do begin
// For each paragraph
s := OriginalText[paragraph]; // Get the original paragraph
// Get the lines in which we have to break the paragraph
while Canvas.TextWidth(s) > MaxLineWidth do begin
// First we find (in 'j') the index of the start of the
// first word that doesn't fit (the one to hyphenate)
j := 1;
n := Length(s);
i := 2;
while i <= n do begin
if (s[i-1] = ' ') and (s[i] <> ' ') then
j := i; // last beginning of a word
if Canvas.TextWidth(Copy(s, 1, i)) > MaxLineWidth then
break; // reached a width that doesn't fit
inc(i);
end;
// Where does the break occurs?
if s[i] = ' ' then begin
// Great! We break on a space
Memo.Lines.Add(Copy(s, 1, i - 1)); // Add the line
s := Copy(s, i + 1, n - i); // Remove the line
end else begin
// We break somewhere in a word. Now, we find (in 'k')
// the first space after the word (k)
k := j + 1;
while (k <= n) and (s[k] <> ' ') do inc(k);
// Divide the word in Syllables
Syllabify(Syllables, Copy(s, j, k - j));
ApplyRules(Syllables);
// Check (in 'm') how many syllables fit
m := 0;
Line := Copy(s, 1, j-1);
while Canvas.TextWidth(Line + Syllables[m] + '-')
<= MaxLineWidth do begin
Line := Line + Syllables[m];
inc(m);
end;
if (m <> 0) and (Syllables[m-1] <> '-') then begin
// Hyphenate
Line := Line + '-';
j := Length(Line);
if Syllables[m] = '-' then inc(j);
end;
Memo.Lines.Add(Line); // Add the line
s := Copy(s, j, n - j + 1); // Remove the line
end;
end;
Memo.Lines.Add(s); // Add the last line (it fits)
end;
finally
Bitmap.Free;
end;
finally
Syllables.Free;
end;
end;
Um die Prozedur zu testen, legen Sie eine Memo-Komponente ein Formular, richten Sie es zum Beispiel an die Spitze des Formulars (Align = AlTop) und schreiben Sie folgenden Code in das Resize-Ereignis des Formulars:
procedure TForm1.FormResize(Sender: TObject);
var
OriginalText: TStringList;
begin
OriginalText := TStringList.Create;
try
OriginalText.Add('Si se ha preguntado como hacen los '
+ 'programas procesamiento de textos para dividir palabras '
+ 'con de guiones al final de una linea, he aqui un '
+ 'ejemplo sencillo (en comparacion con los que usan las '
+ 'aplicaciones de procesamiento de textos).');
OriginalText.Add('Este es un segundo parrafo que se provee '
+ 'con fines de ejemplo.');
Hyphenate(Memo1, OriginalText);
finally
OriginalText.Free;
end;
end;
Den vollständigen Quellcode dieses Artikels finden im Archiv Sie, die begleitenden Newsletter #23 Pascal