]> err.no Git - sope/blob - sope-core/NGExtensions/FdExt.subproj/NSString+German.m
Drop apache 1 build-dependency
[sope] / sope-core / NGExtensions / FdExt.subproj / NSString+German.m
1 /*
2   Copyright (C) 2000-2005 SKYRIX Software AG
3
4   This file is part of SOPE.
5
6   SOPE is free software; you can redistribute it and/or modify it under
7   the terms of the GNU Lesser General Public License as published by the
8   Free Software Foundation; either version 2, or (at your option) any
9   later version.
10
11   SOPE is distributed in the hope that it will be useful, but WITHOUT ANY
12   WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
14   License for more details.
15
16   You should have received a copy of the GNU Lesser General Public
17   License along with SOPE; see the file COPYING.  If not, write to the
18   Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19   02111-1307, USA.
20 */
21
22 #include "NSString+German.h"
23 #include "common.h"
24
25 @implementation NSString(German)
26
27 - (BOOL)doesContainGermanUmlauts {
28   register unsigned i, len;
29   
30   if ((len = [self length]) == 0)
31     return NO;
32   
33   for (i = 0; i < len; i++) {
34     switch ([self characterAtIndex:i]) {
35       case 252: /* &uuml; */
36       case 220: /* &Uuml; */
37       case 228: /* &auml; */
38       case 196: /* &Auml; */
39       case 246: /* &ouml; */
40       case 214: /* &Ouml; */
41       case 223: /* &szlig; */
42         return YES;
43     }
44   }
45   return NO;
46 }
47
48 - (NSString *)stringByReplacingGermanUmlautsWithTwoCharsAndSzWith:(unichar)_c {
49   /*
50     a^ => ae, o^ => oe, u^ => ue, A^ => Ae, O^ => Oe, O^ => Ue
51     s^ => sz or ss (_sz arg)
52   */
53   unsigned i, len, rlen;
54   unichar  *buf;
55   NSString *s;
56   
57   if ((len = [self length]) == 0)
58     return @"";
59   
60   buf = calloc((len * 2) + 3, sizeof(unichar));
61   
62   for (i = 0, rlen = 0; i < len; i++) {
63     // TODO
64     register unichar c;
65     
66     c = [self characterAtIndex:i];
67     switch (c) {
68       case 252: /* ue */
69         buf[rlen] = 'u'; rlen++;
70         buf[rlen] = 'e'; rlen++;
71         break;
72       case 220: /* Ue */
73         buf[rlen] = 'U'; rlen++;
74         buf[rlen] = 'e'; rlen++;
75         break;
76       case 228: /* ae */
77         buf[rlen] = 'a'; rlen++;
78         buf[rlen] = 'e'; rlen++;
79         break;
80       case 196: /* Ae */
81         buf[rlen] = 'A'; rlen++;
82         buf[rlen] = 'e'; rlen++;
83         break;
84       case 246: /* oe */
85         buf[rlen] = 'o'; rlen++;
86         buf[rlen] = 'e'; rlen++;
87         break;
88       case 214: /* Oe */
89         buf[rlen] = 'O'; rlen++;
90         buf[rlen] = 'e'; rlen++;
91         break;
92       case 223: /* ss or sz */
93         // TODO
94         buf[rlen] = 's'; rlen++;
95         buf[rlen] = _c;  rlen++;
96         break;
97         
98     default: /* copy char and continue */
99       buf[rlen] = c;
100       rlen++;
101       break;
102     }
103   }
104   
105   s = (rlen > len)
106     ? [[NSString alloc] initWithCharacters:buf length:rlen]
107     : [self copy];
108   if (buf) free(buf);
109   return [s autorelease];
110 }
111 - (NSString *)stringByReplacingGermanUmlautsWithTwoChars {
112   // default sz mapping is "ss" (like Hess ;-)
113   return [self stringByReplacingGermanUmlautsWithTwoCharsAndSzWith:'s'];
114 }
115
116 - (NSString *)stringByReplacingTwoCharEncodingsOfGermanUmlauts {
117   /*
118     ae => a^, oe => o^, ue => u^, Ae => A^, Oe => O^, Ue => U^
119     sz => s^
120     ss => s^
121   */
122   unsigned i, len, rlen;
123   NSString *s;
124   unichar  *buf;
125   BOOL     didReplace;
126   
127   if ((len = [self length]) == 0)
128     return @"";
129   if (len == 1)
130     return [[self copy] autorelease];
131   
132   buf = calloc(len + 3, sizeof(unichar));
133   [self getCharacters:buf]; // Note: we can reuse that buffer!
134   
135   for (i = 0, rlen = 0, didReplace = NO; i < len; i++) {
136     register unichar c, cn;
137     
138     c = buf[i];
139
140     if ((i + 1) >= len) {
141       buf[rlen] = c;
142       rlen++;
143       break; // end, found last char (so can't be a sequence)
144     }
145
146     cn = buf[i + 1];
147     
148     if ((c=='a' || c=='A' || c=='u' || c=='U' || c=='o' || c=='O')&&cn=='e') {
149       /* an umlaut sequence */
150       switch (c) {
151       case 'a': buf[rlen] = 228; break;
152       case 'A': buf[rlen] = 196; break;
153       case 'o': buf[rlen] = 246; break;
154       case 'O': buf[rlen] = 214; break;
155       case 'u': buf[rlen] = 252; break;
156       case 'U': buf[rlen] = 220; break;
157       }
158       rlen++;
159       i++; // skip sequence char
160       didReplace = YES;
161     }
162     else if (c == 's' && (cn == 's' || cn == 'z')) {
163       /* a sz sequence */
164       buf[rlen] = 223;
165       rlen++;
166       i++; // skip sequence char
167       didReplace = YES;
168     }
169     else {
170       /* regular char, copy */
171       buf[rlen] = c;
172       rlen++;
173     }
174   }
175   
176   s = didReplace
177     ? [[NSString alloc] initWithCharacters:buf length:rlen]
178     : [self copy];
179   if (buf) free(buf);
180   return [s autorelease];
181 }
182
183 - (NSArray *)germanUmlautVariantsOfString {
184   /*
185     The ^ is used to signal the single character umlaut to avoid non-ASCII
186     source code.
187     
188     Note: we can only do a limited set of transformations! Eg you can only
189           mix umlauts *OR* the "ue", "oe" variants!
190     
191     Q: what about names which contain encoded umlauts *and* the same sequence
192        as a regular part of the name! For example "Neuendoerf".
193     
194     string with umlauts (two variants, ss and sz):
195       a^ => ae
196       o^ => oe
197       u^ => ue
198       A^ => Ae
199       O^ => Oe
200       O^ => Ue
201       s^ => sz & ss
202     
203     string with umlaut workaround (three variants due to sz/ss):
204       ae => a^
205       oe => o^
206       ue => u^
207       Ae => A^
208       Oe => O^
209       Ue => U^
210       sz => s^ & sz // ?
211       ss => s^ & ss // ?
212   */
213   NSString *s1, *s2;
214   unsigned len;
215   
216   if ((len = [self length]) == 0)
217     return [NSArray arrayWithObjects:@"", nil];
218   
219   if ([self doesContainGermanUmlauts]) {
220     s1 = [self stringByReplacingGermanUmlautsWithTwoCharsAndSzWith:'s'];
221     s2 = [self stringByReplacingGermanUmlautsWithTwoCharsAndSzWith:'z'];
222     
223     if ([s2 isEqualToString:s1] || [s2 isEqualToString:self])
224       s2 = nil;
225     if ([s1 isEqualToString:self])
226       s1 = s2;
227     
228     return [NSArray arrayWithObjects:self, s1, s2, nil];
229   }
230   
231   if (len < 2) // a sequence would have at least 2 chars
232     return [NSArray arrayWithObjects:self, nil];
233   
234   s1 = [self stringByReplacingTwoCharEncodingsOfGermanUmlauts];
235   
236   if ([self isEqualToString:s1])
237     /* nothing was replaced */
238     return [NSArray arrayWithObjects:self, nil];
239   
240   return [NSArray arrayWithObjects:self, s1, nil];
241 }
242
243 @end /* NSString(German) */