Zeichen: neo_zeichen.php

Datei neo_zeichen.php, 9.6 KB (hinzugefügt von stephan, vor 9 Jahren)

Das Skript, um die Zeichen-Liste zu erstellen, Benutzung auf eigene Gefahr.

Zeile 
1<?php
2        # FIXME Compose auslesen
3
4        # Funktionen
5        # -------------------------------
6
7        # Unicode Codepoint Funktion von http://iki.fi/hsivonen/php-utf8/
8        # (GPL)
9        function utf8ToUnicode(&$str)
10        {
11                $mState = 0;     // cached expected number of octets after the current octet
12                // until the beginning of the next UTF8 character sequence
13                $mUcs4  = 0;     // cached Unicode character
14                $mBytes = 1;     // cached expected number of octets in the current sequence
15
16                $out = array();
17
18                $len = strlen($str);
19                for($i = 0; $i < $len; $i++) {
20                        $in = ord($str{$i});
21                        if (0 == $mState) {
22                                // When mState is zero we expect either a US-ASCII character or a
23                                // multi-octet sequence.
24                                if (0 == (0x80 & ($in))) {
25                                        // US-ASCII, pass straight through.
26                                        $out[] = $in;
27                                        $mBytes = 1;
28                                } else if (0xC0 == (0xE0 & ($in))) {
29                                        // First octet of 2 octet sequence
30                                        $mUcs4 = ($in);
31                                        $mUcs4 = ($mUcs4 & 0x1F) << 6;
32                                        $mState = 1;
33                                        $mBytes = 2;
34                                } else if (0xE0 == (0xF0 & ($in))) {
35                                        // First octet of 3 octet sequence
36                                        $mUcs4 = ($in);
37                                        $mUcs4 = ($mUcs4 & 0x0F) << 12;
38                                        $mState = 2;
39                                        $mBytes = 3;
40                                } else if (0xF0 == (0xF8 & ($in))) {
41                                        // First octet of 4 octet sequence
42                                        $mUcs4 = ($in);
43                                        $mUcs4 = ($mUcs4 & 0x07) << 18;
44                                        $mState = 3;
45                                        $mBytes = 4;
46                                } else if (0xF8 == (0xFC & ($in))) {
47                                        /* First octet of 5 octet sequence.
48                                        *
49                                        * This is illegal because the encoded codepoint must be either
50                                        * (a) not the shortest form or
51                                        * (b) outside the Unicode range of 0-0x10FFFF.
52                                        * Rather than trying to resynchronize, we will carry on until the end
53                                        * of the sequence and let the later error handling code catch it.
54                                        */
55                                        $mUcs4 = ($in);
56                                        $mUcs4 = ($mUcs4 & 0x03) << 24;
57                                        $mState = 4;
58                                        $mBytes = 5;
59                                } else if (0xFC == (0xFE & ($in))) {
60                                        // First octet of 6 octet sequence, see comments for 5 octet sequence.
61                                        $mUcs4 = ($in);
62                                        $mUcs4 = ($mUcs4 & 1) << 30;
63                                        $mState = 5;
64                                        $mBytes = 6;
65                                } else {
66                                        /* Current octet is neither in the US-ASCII range nor a legal first
67                                        * octet of a multi-octet sequence.
68                                        */
69                                        return false;
70                                }
71                        } else {
72                                // When mState is non-zero, we expect a continuation of the multi-octet
73                                // sequence
74                                if (0x80 == (0xC0 & ($in))) {
75                                        // Legal continuation.
76                                        $shift = ($mState - 1) * 6;
77                                        $tmp = $in;
78                                        $tmp = ($tmp & 0x0000003F) << $shift;
79                                        $mUcs4 |= $tmp;
80                                        if (0 == --$mState) {
81                                                /* End of the multi-octet sequence. mUcs4 now contains the final
82                                                * Unicode codepoint to be output
83                                                *
84                                                * Check for illegal sequences and codepoints.
85                                                */
86                                                // From Unicode 3.1, non-shortest form is illegal
87                                                if (((2 == $mBytes) && ($mUcs4 < 0x0080)) ||
88                                                ((3 == $mBytes) && ($mUcs4 < 0x0800)) ||
89                                                ((4 == $mBytes) && ($mUcs4 < 0x10000)) ||
90                                                (4 < $mBytes) ||
91                                                // From Unicode 3.2, surrogate characters are illegal
92                                                (($mUcs4 & 0xFFFFF800) == 0xD800) ||
93                                                // Codepoints outside the Unicode range are illegal
94                                                ($mUcs4 > 0x10FFFF)) {
95                                                        return false;
96                                                }
97                                                if (0xFEFF != $mUcs4) {
98                                                        // BOM is legal but we don't want to output it
99                                                        $out[] = $mUcs4;
100                                                }
101                                                //initialize UTF8 cache
102                                                $mState = 0;
103                                                $mUcs4  = 0;
104                                                $mBytes = 1;
105                                        }
106                                } else {
107                                        /* ((0xC0 & (*in) != 0x80) && (mState != 0))
108                                        *
109                                        * Incomplete multi-octet sequence.
110                                        */
111                                        return false;
112                                }
113                        } # if state ...
114                } # for-loop
115                return $out;
116        }
117
118        # Liest alle Tasten, samt zugehörigen Zeichen aus der Referenz
119        function getNeoKeys () {
120                # Referenz laden
121                $reference = file_get_contents('http://neo-layout.org/svn/A-REFERENZ-A/neo20.txt');
122
123                # Haupttastatur finden
124                preg_match('/┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────────┐\n(.*)\n└──────┴──────┴──────┴──────────────────────────────────────┴──────┴──────┴──────┴──────┘/s', $reference, $found);
125                # Tastaturreihen aufspalten
126                $rows = preg_split('/\n├.*\n/', $found[1]);
127
128                $n = 1;
129                # Für jede Reihe:
130                foreach ($rows as $row) {
131                        $sub_rows = preg_split('/\n/', $row);
132
133                        # Finde Zeichen in beiden Zeilen.
134                        # U030F ist ein combining-character und tritt zusammen mit einem Leerzeichen auf, damit es angezeigt wird
135                        preg_match_all('/│(.) (\x{030F} |.) (.)(?=│)/u', $sub_rows[0], $r1);
136                        preg_match_all('/│(.) (.) (.)(?=│)/u', $sub_rows[1], $r2);
137
138                        # Für jede Taste:
139                        for ($i = 0; $i < count($r1[0]); $i++) {
140                                # Überspringe Enter-Taste, die nicht dazugehört
141                                if ($r1[2][$i] == "\xE2\x86\xB2" && $i == 11) {
142                                        $n--;
143                                        continue;
144                                }
145                                # Lade die Zeichen der beiden Zeilen in das Array, geordnet nach ihrer Ebene
146                                $key[$n+$i.'_1'] = $r2[1][$i];
147                                $key[$n+$i.'_2'] = $r1[1][$i];
148                                $key[$n+$i.'_3'] = $r2[2][$i];
149                                $key[$n+$i.'_4'] = $r1[2][$i];
150                                $key[$n+$i.'_5'] = $r2[3][$i];
151                                $key[$n+$i.'_6'] = $r1[3][$i];
152                        }
153                        $n += $i;
154                }
155                return $key;
156        }
157
158        # Nutzt utf8ToUnicode(), um einen Unicode-Codepoint zu finden, der dann hexadezimal formatiert zurückgegeben wird.
159        function getUnicodeCodepoint ($char) {
160                $codepoints = utf8ToUnicode($char);
161                if (!$codepoints[0]) return false;
162                return strtoupper(str_pad(dechex($codepoints[0]), 4, "0", STR_PAD_LEFT));
163        }
164
165
166
167        # Unicode Daten für die Zeichen-Benennung holen.
168        # ----------------------------------------------
169        ini_set('memory_limit', '128M');
170        # Sehr hoher Speicherbedarf, deshalb wäre es eigentlich besser UnicodeData in einer Datenbank zu haben
171        $ucdfull = file_get_contents('http://www.unicode.org/Public/UNIDATA/UnicodeData.txt');
172        $ucdfull = explode("\n", $ucdfull);
173        # Array erstellen, um leichter auf die Daten zugreifen zu können
174        $ucd = array();
175        foreach ($ucdfull as $chardata) {
176                $chardata = explode(';', $chardata);
177                $ucd[$chardata[0]] = $chardata;
178        }
179
180        # Erzeugbare Zeichen suchen
181        # ---------------------------------------------
182
183        # Alle Tasten mit ihren Zeichen aus der Referenz laden
184        $keys = getNeoKeys();
185
186        # Diese Zeichen müssen noch angehäng werden, da die Leertaste nicht eingelesen wird
187        # Position der Zeichen ist irrelevant, siehe weiter unten
188        $keys[] = ' '; # SPACE
189        $keys[] = ' '; # NO-BREAK SPACE
190        $keys[] = ' '; # NARROW NO-BREAK SPACE
191
192        # Duplikate entfernen und alles sortieren
193        $chars = array_unique($keys);
194
195
196        sort($chars);
197
198        # Für jedes Zeichen die Kombination(en) auslesen, mit der/denen es erzeugt werden kann
199        # ------------------------------------------------
200
201        foreach ($chars as $char) {
202                $char = array('char' => $char);
203
204                # Ausnahmen, deren Kombinationen falsch sind, oder uns nicht interessieren:
205                # Diese Zeichen werden nicht erstellt, sondern sind in der Referenz nur zur Verdeutlichung da.
206                if (in_array($char['char'], array('⇞','⇟','⇠','⇡','⇢','⇣','⇱','⇲','⇥','⌦','⌧','⌫','↲','↶','⎀'))) continue; # Control-Keys
207                # Auch die Toten Tasten werden nicht normal erzeugt. Deren Zeichen können aber durch Auslesen der Compose gewonnen werden.
208                if (in_array($char['char'], array('˜','ˇ','¯','ˆ','˚','˘',"\xCC\x8F\x20",'`','¨','῾','¸','˝','˙','´','᾿'))) continue; # Dead-Keys
209
210                $char['codepoint'] = 'U+' . getUnicodeCodepoint($char['char']);
211                # Namen des Zeichens aus der UnicodeData auslesen
212                $char['name'] = $ucd[getUnicodeCodepoint($char['char'])][1];
213
214                # Da $keys mit den Positionen als Index angeordnet ist, bietet es sich an,
215                # das Array umzukehren und gleichzeitig nach dem entsprechenden Zeichen zu suchen
216                $char_positions = array_keys($keys, $char['char'], true);
217
218                $char['combos'] = array();
219                foreach ($char_positions as $pos) {
220                        # Tastenposition aus Arraywert lesen
221                        $keypos = substr($pos, 0, strpos($pos, '_'));
222                        # Keine Toten Tasten absuchen, würde sonst z.B. "<Mod3> + <´>" für SOLIDUS finden
223                        if (in_array($keypos, array('1', '13', '25'))) continue; # 1 ≙ T1; 13 ≙ T2; 25 ≙ T3
224
225                        # Je nach Level werden unterschiedliche Modifier gebraucht
226                        $level = substr($pos, -1);
227                        switch ($level) {
228                                case '1':
229                                        $combo = '<{{{' . $keys[$keypos . '_1'] . '}}}>';
230                                        break;
231                                case '2':
232                                        $combo = '<Shift> + <{{{' . $keys[$keypos . '_1'] . '}}}>';
233                                        break;
234                                case '3':
235                                        $combo = '<Mod3> + <{{{' . $keys[$keypos . '_1'] . '}}}>';
236                                        break;
237                                case '4':
238                                        $combo = '<Mod4> + <{{{' . $keys[$keypos . '_1'] . '}}}>';
239                                        break;
240                                case '5':
241                                        $combo = '<Shift> + <Mod3> + <{{{' . $keys[$keypos . '_1'] . '}}}>';
242                                        break;
243                                case '6':
244                                        $combo = '<Mod3> + <Mod4> + <{{{' . $keys[$keypos . '_1'] . '}}}>';
245                                        break;
246
247                        }
248                        $char['combos'][] = $combo;
249
250                }
251                # Die Leertaste hat keine Positionierung, deshalb manuelle Namensvergabe
252                # Das Leerzeichen tritt in der Referenz leider mehrfach auf (an Stellen, die noch Leer sind):
253                if ($char['name'] == 'SPACE') $char['combos'] = array('<Leertaste>');
254                if ($char['name'] == 'DIGIT ZERO') $char['combos'][] = '<Mod4> + <Leertaste>';
255                if ($char['name'] == 'NO-BREAK SPACE') $char['combos'] = array('<Shift> + <Mod3> + <Leertaste>');
256                if ($char['name'] == 'NARROW NO-BREAK SPACE') $char['combos'] = array('<Mod3> + <Mod4> + <Leertaste>');
257
258                # FIXME Sortieren der Combos, einfachste zuerst.
259
260                # Zusammensetzen der Variablen und Ausgabe als wiki-formatierte Tabelle.
261                # ------------------------------------------------
262                echo '||{{{' . $char['char'] . '}}}||' . $char['codepoint'] . '||' . $char['name'] . '||' .  implode('[[BR]]', $char['combos'])  . '||' . "\n";
263        }
264
265?>