OLD | NEW |
| (Empty) |
1 # -*- test-case-name: twisted.test.test_text -*- | |
2 # | |
3 # Copyright (c) 2001-2004 Twisted Matrix Laboratories. | |
4 # See LICENSE for details. | |
5 | |
6 | |
7 """Miscellany of text-munging functions. | |
8 """ | |
9 | |
10 import string, types | |
11 | |
12 def stringyString(object, indentation=''): | |
13 """Expansive string formatting for sequence types. | |
14 | |
15 list.__str__ and dict.__str__ use repr() to display their | |
16 elements. This function also turns these sequence types | |
17 into strings, but uses str() on their elements instead. | |
18 | |
19 Sequence elements are also displayed on seperate lines, | |
20 and nested sequences have nested indentation. | |
21 """ | |
22 braces = '' | |
23 sl = [] | |
24 | |
25 if type(object) is types.DictType: | |
26 braces = '{}' | |
27 for key, value in object.items(): | |
28 value = stringyString(value, indentation + ' ') | |
29 if isMultiline(value): | |
30 if endsInNewline(value): | |
31 value = value[:-len('\n')] | |
32 sl.append("%s %s:\n%s" % (indentation, key, value)) | |
33 else: | |
34 # Oops. Will have to move that indentation. | |
35 sl.append("%s %s: %s" % (indentation, key, | |
36 value[len(indentation) + 3:])) | |
37 | |
38 elif type(object) in (types.TupleType, types.ListType): | |
39 if type(object) is types.TupleType: | |
40 braces = '()' | |
41 else: | |
42 braces = '[]' | |
43 | |
44 for element in object: | |
45 element = stringyString(element, indentation + ' ') | |
46 sl.append(string.rstrip(element) + ',') | |
47 else: | |
48 sl[:] = map(lambda s, i=indentation: i+s, | |
49 string.split(str(object),'\n')) | |
50 | |
51 if not sl: | |
52 sl.append(indentation) | |
53 | |
54 if braces: | |
55 sl[0] = indentation + braces[0] + sl[0][len(indentation) + 1:] | |
56 sl[-1] = sl[-1] + braces[-1] | |
57 | |
58 s = string.join(sl, "\n") | |
59 | |
60 if isMultiline(s) and not endsInNewline(s): | |
61 s = s + '\n' | |
62 | |
63 return s | |
64 | |
65 def isMultiline(s): | |
66 """Returns True if this string has a newline in it.""" | |
67 return (string.find(s, '\n') != -1) | |
68 | |
69 def endsInNewline(s): | |
70 """Returns True if this string ends in a newline.""" | |
71 return (s[-len('\n'):] == '\n') | |
72 | |
73 def docstringLStrip(docstring): | |
74 """Gets rid of unsightly lefthand docstring whitespace residue. | |
75 | |
76 You'd think someone would have done this already, but apparently | |
77 not in 1.5.2. | |
78 | |
79 BUT since we're all using Python 2.1 now, use L{inspect.getdoc} | |
80 instead. I{This function should go away soon.} | |
81 """ | |
82 | |
83 if not docstring: | |
84 return docstring | |
85 | |
86 docstring = string.replace(docstring, '\t', ' ' * 8) | |
87 lines = string.split(docstring,'\n') | |
88 | |
89 leading = 0 | |
90 for l in xrange(1,len(lines)): | |
91 line = lines[l] | |
92 if string.strip(line): | |
93 while 1: | |
94 if line[leading] == ' ': | |
95 leading = leading + 1 | |
96 else: | |
97 break | |
98 if leading: | |
99 break | |
100 | |
101 outlines = lines[0:1] | |
102 for l in xrange(1,len(lines)): | |
103 outlines.append(lines[l][leading:]) | |
104 | |
105 return string.join(outlines, '\n') | |
106 | |
107 def greedyWrap(inString, width=80): | |
108 """Given a string and a column width, return a list of lines. | |
109 | |
110 Caveat: I'm use a stupid greedy word-wrapping | |
111 algorythm. I won't put two spaces at the end | |
112 of a sentence. I don't do full justification. | |
113 And no, I've never even *heard* of hypenation. | |
114 """ | |
115 | |
116 outLines = [] | |
117 | |
118 #eww, evil hacks to allow paragraphs delimited by two \ns :( | |
119 if inString.find('\n\n') >= 0: | |
120 paragraphs = string.split(inString, '\n\n') | |
121 for para in paragraphs: | |
122 outLines.extend(greedyWrap(para) + ['']) | |
123 return outLines | |
124 inWords = string.split(inString) | |
125 | |
126 column = 0 | |
127 ptr_line = 0 | |
128 while inWords: | |
129 column = column + len(inWords[ptr_line]) | |
130 ptr_line = ptr_line + 1 | |
131 | |
132 if (column > width): | |
133 if ptr_line == 1: | |
134 # This single word is too long, it will be the whole line. | |
135 pass | |
136 else: | |
137 # We've gone too far, stop the line one word back. | |
138 ptr_line = ptr_line - 1 | |
139 (l, inWords) = (inWords[0:ptr_line], inWords[ptr_line:]) | |
140 outLines.append(string.join(l,' ')) | |
141 | |
142 ptr_line = 0 | |
143 column = 0 | |
144 elif not (len(inWords) > ptr_line): | |
145 # Clean up the last bit. | |
146 outLines.append(string.join(inWords, ' ')) | |
147 del inWords[:] | |
148 else: | |
149 # Space | |
150 column = column + 1 | |
151 # next word | |
152 | |
153 return outLines | |
154 | |
155 | |
156 wordWrap = greedyWrap | |
157 | |
158 def removeLeadingBlanks(lines): | |
159 ret = [] | |
160 for line in lines: | |
161 if ret or line.strip(): | |
162 ret.append(line) | |
163 return ret | |
164 | |
165 def removeLeadingTrailingBlanks(s): | |
166 lines = removeLeadingBlanks(s.split('\n')) | |
167 lines.reverse() | |
168 lines = removeLeadingBlanks(lines) | |
169 lines.reverse() | |
170 return '\n'.join(lines)+'\n' | |
171 | |
172 def splitQuoted(s): | |
173 """Like string.split, but don't break substrings inside quotes. | |
174 | |
175 >>> splitQuoted('the \"hairy monkey\" likes pie') | |
176 ['the', 'hairy monkey', 'likes', 'pie'] | |
177 | |
178 Another one of those \"someone must have a better solution for | |
179 this\" things. This implementation is a VERY DUMB hack done too | |
180 quickly. | |
181 """ | |
182 out = [] | |
183 quot = None | |
184 phrase = None | |
185 for word in s.split(): | |
186 if phrase is None: | |
187 if word and (word[0] in ("\"", "'")): | |
188 quot = word[0] | |
189 word = word[1:] | |
190 phrase = [] | |
191 | |
192 if phrase is None: | |
193 out.append(word) | |
194 else: | |
195 if word and (word[-1] == quot): | |
196 word = word[:-1] | |
197 phrase.append(word) | |
198 out.append(" ".join(phrase)) | |
199 phrase = None | |
200 else: | |
201 phrase.append(word) | |
202 | |
203 return out | |
204 | |
205 def strFile(p, f, caseSensitive=True): | |
206 """Find whether string p occurs in a read()able object f | |
207 @rtype: C{bool} | |
208 """ | |
209 buf = "" | |
210 buf_len = max(len(p), 2**2**2**2) | |
211 if not caseSensitive: | |
212 p = p.lower() | |
213 while 1: | |
214 r = f.read(buf_len-len(p)) | |
215 if not caseSensitive: | |
216 r = r.lower() | |
217 bytes_read = len(r) | |
218 if bytes_read == 0: | |
219 return False | |
220 l = len(buf)+bytes_read-buf_len | |
221 if l <= 0: | |
222 buf = buf + r | |
223 else: | |
224 buf = buf[l:] + r | |
225 if buf.find(p) != -1: | |
226 return True | |
227 | |
OLD | NEW |