【问题标题】:Grab the lines where the tags were not substituted in a text file抓取文本文件中未替换标签的行
【发布时间】:2019-05-22 15:46:05
【问题描述】:

我的代码遇到了一个大问题。

TL;DR:在几次 cmet 之后,我决定将整个代码发布在这里:

https://repl.it/repls/AustereShinyBetatest

这是我的代码:

def highlight_nonmodified(content: str) -> str:
    regex = re.compile(r'(?s)(\{.*?[^\}]+\})', re.I | re.S)
    replace = r'#\1'
    content = regex.sub(replace, content)
    return content


def get_line(string_t: str, original: str) -> int:
    original = original.splitlines(True)
    for (i, line) in enumerate(original, 1):
        if string_t[1:] in line:
            return i

    return -1


def highligh_merge(original: str, modified: str) -> str:
    for line in modified.splitlines(True):
        if line.startswith('#'):
            numer = get_line(line, original)
            error = r"#Tag not supported at line{0}\n".format(numer)
            error = error + line
            modified = modified.replace(line, error)

我的问题是会发生以下情况:

Textfile.txt(原件):

1. Here goes some text. {tag} A wonderful day. It's soon cristmas. 
2. Happy 2019, soon. {Some useful tag!} Something else goes here. 
3. Happy ending. Yeppe! See you. 
4. 
5  Happy KKK! 
6. Happy B-Day!
7 
8. Universe is cool!
9.
10. {Tagish}. 
11.
12. {Slugish}. Here goes another line. {Slugish} since this is a new sentence. 
13.
14. endline.

修改后的.txt:

Here goes some text.  A wonderful day. It's soon cristmas. 
Happy 2019, soon. #{Some useful tag!} Something else goes here. 
Happy ending. Yeppe! See you. 

Happy KKK! 
Happy B-Day!

Universe is cool!

. 

#Error: Tag not supported at line-1\n#{Slugish}. Here goes another line. #{Slugish} since this is a new sentence. 

endline. 

我似乎无法获得精确的行号和行比较,我在这里做错了什么,我显然是存储了两个副本,原始和修改,然后我选择然后我尝试选择通过逐行循环从原始文本中取出行号。但仍然没有任何成功,这是否可能。提前非常感谢!

【问题讨论】:

  • 您能指出修改后的文件中的“错误”和“没有成功”吗?只是说它是错误的可能实际上是正确的,但这并不能帮助我们帮助您。
  • 请参阅 original.txt 和 modified.txt 以获得说明。
  • 我看到它们是不同的。但哪些差异是“错误的”,哪些不是?
  • 我已经手动添加了行,所以如果某些标签没有被删除,我想在 original.txt 中写出它所在的行号
  • 不清楚highlight_nonmodifiedhighligh_merge这两个函数是如何使用的,或者以什么顺序使用;我会澄清你的问题,包括一个小驱动程序,准确地展示你如何接受一些样本输入,处理它,然后把它吐出来。这也有助于澄清 Modified.txt 是“错误的输出”,而 End result 是“期望的输出”。

标签: python string text


【解决方案1】:

当您在highligh_merge 中调用函数get_line 时,您正在使用修改后的line 变量执行它,因此line 将永远不会真正位于原始文本文件中。如果你看line的值:

#{Slugish}. Here goes another line. #{Slugish} since this is a new sentence.

您可以看到,这显然不在原始的 textfile.txt 中。因此,这将返回 -1 的行号。

对此的解决方案是更改 highligh_merge 函数中的 for 循环:

for line in modified.splitlines(True):

收件人:

for numer, line in enumerate(modified.splitlines(True)):

现在,每次迭代中的numer 等于行数 - 1。只需使用 numer + 1 即可获得您正在处理的行的确切行数。

我希望这会有所帮助。 :)

【讨论】:

  • 我仍在努力,但如果有人可以提供更多详细信息,我很乐意学习。如果这肯定证实我走在正确的道路上,那么我会将赏金赠予应得的用户。
  • 两者都有。你有所有代码的链接。
  • 不,我将文件复制到我计算机上的一个文件夹中并使用 Python 3 运行它。您使用的是 Python 3,不是吗?
  • 也许我就是,谁知道呢!
  • 你的结果是什么?也许你可以使用 repl.it 并分享运行代码!
【解决方案2】:

下面是一个简短的脚本,用于导入文件、清理数据、创建枚举字典和输出结果(可选,基于 print_results 变量)。

(如果我没有正确解释您的问题,请告诉我!)

import re
from os import path

"""
Create an error class for trying to close a file that isn't open.
"""
class FileException(Exception):
    pass

class FileNotOpenError(FileException):
    pass

"""
Input variables.  base_path is just the directory where your files are located.
If they are in different directories, then use a second variable.
"""
base_path = r'C:\..\[folder containing text files]'
original_filename = 'test_text.txt'
modified_filename = 'modified_text.txt'


def import_data(file_name, root=base_path):
    """
    Read each text file into a list of lines.
    """
    full_path = path.join(root, file_name)

    with open(full_path, 'r') as f:
        data = f.readlines()

    try:
        f.close()
    except FileNotOpenError:
        pass

    if len(data) > 0:
        return data


def remove_numbering(input):
    """
    RegEx to clean data; This will remove only the line numbers and not
    any subsequent number-period combinations in the line.
    """
    p = re.compile(r'^([0-9]+[.]?\s)')
    return p.sub('', input)


def text_dict(text_list):
    """
    Remove numbering from either file; Considers period punctuation following number.
    """
    new_text = [remove_numbering(i).lstrip() for i in text_list]
    return {idx+1:val for idx, val in enumerate(new_text)}


def compare_files(original, modified, missing_list=None):

    # Create a fresh list (probably not necessary)
    if missing_list is None:
        missing_list = list()

    # Ensure that data types are dictionaries.
    if isinstance(original, dict) and isinstance(_modified, dict):
        # Use list comprehension to compare lines in each file.
        # Modified line numbers will end up in a list, which we will return.
        modified_index_list = [idx for idx in original.keys() if original[idx] != modified[idx]]

    # Check to see if list exists; Return it if it does.
    # if len(modified_index_list) > 0:
    if not modified_index_list is None:
        return modified_index_list


def comparison_findings(missing_list, original_dict, modified_dict):
    print('Modifications found on lines:\n- ' + '\n- '.join([str(i) for i in missing_list]))
    print('\n\n\tOriginal:\n')
    max_len = max([len(original_dict[i].replace('\n','').rstrip()) for i in original_dict.keys() if i in missing_list])
    print('\t\t{0:^7}{1:^{x}}'.format('Line','Value',x=max_len))
    for i in missing_list:
        temp_val = original_dict[i].replace('\n','').rstrip()
        print('\t\t{0:>5}{1:2}{2:<{x}}'.format(str(i), '', temp_val, x=max_len))
    print('\n\n\tModified:\n')
    max_len = max([len(modified_dict[i].replace('\n','').rstrip()) for i in modified_dict.keys() if i in missing_list])
    print('\t\t{0:^7}{1:^{x}}'.format('Line','Value',x=max_len))
    for i in xyz:
        temp_val = modified_dict[i].replace('\n','').rstrip()
        print('\t\t{0:>5}{1:2}{2:<{x}}'.format(str(i), '', temp_val, x=max_len))



if __name__ == '__main__':
    print_results = True

    # Import text files.
    orig_data = import_data(original_filename)
    mod_data = import_data(modified_filename)

    # Create enumerated dictionaries from text files.
    _original = text_dict(orig_data)
    _modified = text_dict(mod_data)

    # Get a list of modified lines.
    mod_list = compare_files(_original, _modified)

    # Output results of file comparison.
    if print_results:
        comparison_findings(mod_list, _original, _modified)

【讨论】:

  • xyz 未定义?
  • 我想抓取标签未被正则表达式替换的行!
  • @JohnSmith 在 xyz 上:哎呀!接得好。我仍然是在这里发帖的新手并且错过了。我认为 xyz 应该是 missing_list 参数,所以我会更新提交。
  • @JohnSmith 你的意思是列号还是行号?如果你想找出“#”出现在哪里,那么你可以使用 str.index('#')。 txt = 'Happy 2019, soon. #{Some useful tag!} Something else goes here. ' txt.index('#')
  • @JohnSmith 好的,我有点慢,仍然很难掌握这一点。你是说,例如,在原始文本文件的第 1 行,如果 {tag} 被删除,你想知道它被删除,它在第 1 行,以及标签是什么,并显示那些注释在修改后的文本文件中?再一次,对不起,如果我不太明白!
【解决方案3】:

如果多行文本块可能已被删除,我认为无法做到这一点。但是,如果您控制标记过程,则可以在标记中包含原始行号:

{ foo:12 }

然后恢复它是微不足道的

original = int(re.search(r'\d+', tag).group(0))

您的代码的修改版本:

import re                                                                                                                        


def annotate_tags(content: str) -> str:                                                                                          
    """Annotate tags with line numbers."""                                                                                       
    tag_pattern = re.compile(r'(\{(?P<tag_value>[^}]+)\})')                                                                      
    lines = content.splitlines(True)                                                                                             
    annotated_lines = []                                                                                                         
    for idx, line in enumerate(lines, 1):                                                                                        
        annotated_lines.append(tag_pattern.sub(r'{\g<tag_value>:%s}' % idx, line))                                               
    annotated = ''.join(annotated_lines)                                                                                         
    return annotated                                                                                                             


def modify(content: str) -> str:                                                                                                 
    supported_tags = {                                                                                                           
            re.compile(r'(\{tag:\d+\})'): r'',                                                                                   
            re.compile(r'(\{Tagish:\d+\})'): r''                                                                                 
    }                                                                                                                            

    for pattern, replace in supported_tags.items():                                                                              
        matches = pattern.findall(content)                                                                                       
        if matches:                                                                                                              
            content = pattern.sub(replace, content)                                                                              

    return content                                                                                                               


def highlight_nonmodified(content: str) -> str:                                                                                  
    regex = re.compile(r'(?s)(\{.*?[^\}]+\})', re.I | re.S)                                                                      
    replace = r'#\1'                                                                                                             
    content = regex.sub(replace, content)                                                                                        
    return content                                                                                                               


def get_line(string_t: str, original: str) -> int:                                                                               
    tag_pattern = re.compile(r'(\{[^}]+:(?P<line_no>\d+)\})')                                                                    
    match = tag_pattern.search(string_t)                                                                                         
    if match:                                                                                                                    
        return match.group('line_no')                                                                                            
    return -1                                                                                                                    


def highlight_merge(original: str, modified: str) -> str:                                                                        
    tag_regex = re.compile(r'#(?s)(\{.*?[^\}]+\})', re.I | re.S)                                                                 
    for line in modified.splitlines(True):                                                                                       
        if tag_regex.search(line):                                                                                               
            numer = get_line(line, original)                                                                                     
            error = "#Tag not supported at line{0}\n".format(numer)                                                              
            error = error + line
            modified = modified.replace(line, error)
    return modified


if __name__ == '__main__':
    file = 'textfile.txt'
    raw = ""
    with open(file, 'rt', encoding='utf-8') as f:
        for i, s in enumerate(f, 1):
            raw += "{}. {}".format(i, s)

    original = modified = raw

    modified = annotate_tags(modified)
    modified = modify(modified)
    modified = highlight_nonmodified(modified)
    modified = highlight_merge(original, modified)

    with open("modified.txt", 'w', encoding='utf-8') as f:
        f.write(modified)

生成此输出:

1. Here goes some text.  A wonderful day. It's soon cristmas. 
#Tag not supported at line2
2. Happy 2019, soon. #{Some useful tag!:2} Something else goes here. 
3. Happy ending. Yeppe! See you. 
4. 
#Tag not supported at line5
5. #{begin:5}
6. Happy KKK! 
7. Happy B-Day!
#Tag not supported at line8
8. #{end:8}
9. 
10. Universe is cool!
11. 
12. . 
13. 
#Tag not supported at line14
14. #{Slugish:14}. Here goes another line. #{Slugish:14} since this is a new sentence. 
15. 
16. endline.

【讨论】:

  • 如何使用块来实现?假设:{begin} .... {end},意思是,这可能会覆盖大部分行号。你在这里提出了一个有效的观点。
  • 我猜你可以将块的第一行号添加到开始标记,将最后的行号添加到结束标记?
  • 你能更清楚地解释你认为什么行不通吗?
  • 我认为包含这样一个块的输入文件的示例以及预期的输出将是对问题的有用补充。
  • @JohnSmith 我已经添加了代码和输出。你能否确认输出是你想要的,或者解释一下可能需要什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-06
  • 1970-01-01
  • 1970-01-01
  • 2012-02-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多