套管文本取决于标点符号

时间:2012-12-07 04:10:02

标签: python text formatting state-machine

根据标点符号和修复格式(空白等),将文本更改为正确的最有效方法是什么?

the qUiCk BROWN fox:: jumped. over , the lazy    dog.

期望的结果:

The quick brown fox: jumped. Over, the lazy dog.

2 个答案:

答案 0 :(得分:2)

您标记了您的问题“正则表达式”但我不建议使用正则表达式来尝试解决此问题。最好使用简单的状态机来处理。

这是一个足以处理你的例子的简单状态机。如果你在其他文本上尝试它,你可能会发现它无法处理的情况;我希望你会发现它的设计清晰,你可以毫不费力地修改它以适应你的目的。

import string

s = "the qUiCk BROWN fox:: jumped. over , the lazy    dog."
s_correct = "The quick brown fox: jumped. Over, the lazy dog."


def chars_from_lines(lines):
    for line in lines:
        for ch in line:
            yield ch

start, in_sentence, saw_space = range(3)

punct = set(string.punctuation)
punct_non_repeat = punct - set(['.', '-'])
end_sentence_chars = set(['.', '!', '?'])

def edit_sentences(seq):
    state = start
    ch_punct_last = None

    for ch in seq:
        ch = ch.lower()

        if ch == ch_punct_last:
            # Don't pass repeated punctuation.
            continue
        elif ch in punct_non_repeat:
            ch_punct_last = ch
        else:
            # Not punctuation to worry about, so forget the last.
            ch_punct_last = None

        if state == start and ch.isspace():
            continue
        elif state == start:
            state = in_sentence
            yield ch.upper()

        elif state == in_sentence and ch in end_sentence_chars:
            state = start
            yield ch
            yield ' '
        elif state == in_sentence and not ch.isspace():
            yield ch
        elif state == in_sentence and ch.isspace():
            state = saw_space
            continue

        elif state == saw_space and ch.isspace():
            # stay in state saw_space
            continue
        elif state == saw_space and ch in punct:
            # stay in state saw_space
            yield ch
        elif state == saw_space and ch.isalnum():
            state = in_sentence
            yield ' '
            yield ch

#with open("input.txt") as f:
#    s_result = ''.join(ch for ch in edit_sentences(chars_from_lines(f)))

s_result = ''.join(ch for ch in edit_sentences(s))

print(s_result)
print(s_correct)

答案 1 :(得分:1)

假设line是输入字符串。以下应该做一些非常接近你想要的事情。请注意,换行符(和其他空格)将转换为单个空格。

import string    # used to check if a character is a letter
#assume we start with a letter and not, for instance, a quotation mark
assert line[0] in string.letters
line = line.capitalize()
duplPunct = [] #list of indices of duplicate punctuation
prev = line[0]
for i in range(len(line))[1:]:
    if line[i] == prev and prev not in string.letters:
        duplPunct.append(i)
    prev = line[i]
while len(duplPunct):
    i = duplPunct.pop()    #returns last index needing deletion
    line = line[:i]+line[i+1:]
words = line.split() #removes all whitespace
floatingchar = []  #list of indices of words containing only a single invalid character
for i in range(len(words))[1:]:
    word = words[i]
    if len(word) == 1 and word not in 'ai':
        #assume single-character 'words' should be part of previous word
        floatingchar.append(i)
while len(floatingchar):
    i = floatingchar.pop()
    words[i-1] = words[i-1]+words[i]
    del words[i]
needCaps = [] #list of indices of words requiring capitalization
for i in range(len(words))[:-1]:
    if words[i][-1] in '.!?':
        needCaps.append(i+1)
while len(needCaps):
    i = needCaps.pop()
    words[i] = words[i].capitalize()
line = ' '.join(words)