| 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 |