提取 .txt 文件中两个关键字之间的所有单词

Posted

技术标签:

【中文标题】提取 .txt 文件中两个关键字之间的所有单词【英文标题】:Extract all words between two keywords in .txt file 【发布时间】:2020-04-05 00:30:26 【问题描述】:

我想提取 .txt 文件中特定关键字中的所有单词。对于关键字,有一个起始关键字PROC SQL;(我需要它不区分大小写),结束关键字可以是RUN;quit;QUIT;。这是我的示例.txt file。

到目前为止,这是我的代码:

with open('lan sample text file1.txt') as file:
    text = file.read()
    regex = re.compile(r'(PROC SQL;|proc sql;(.*?)RUN;|quit;|QUIT;)')
    k = regex.findall(text)
    print(k)

输出:

[('quit;', ''), ('quit;', ''), ('PROC SQL;', '')]

但是,我的预期输出是获取介于关键字之间的单词:

proc sql; ("TRUuuuth");
hhhjhfjs as fdsjfsj:
select * from djfkjd to jfkjs
(
SELECT abc AS abc1, abc_2_ AS efg, abc_fg, fkdkfj_vv, jjsflkl_ff, fjkdsf_jfkj
    FROM &xxx..xxx_xxx_xxE
where ((xxx(xx_ix as format 'xxxx-xx') gff &jfjfsj_jfjfj.) and 
      (xxx(xx_ix as format 'xxxx-xx') lec &jgjsd_vnv.))
 );

1)

jjjjjj;

  select xx("xE'", PUT(xx.xxxx.),"'") jdfjhf:jhfjj from xxxx_x_xx_L ;
quit; 

PROC SQL; ("CUuuiiiiuth");
hhhjhfjs as fdsjfsj:
select * from djfkjd to jfkjs
(SELECT abc AS abc1, abc_2_ AS efg, abc_fg, fkdkfj_vv, jjsflkl_ff, fjkdsf_jfkj
    FROM &xxx..xxx_xxx_xxE
where ((xxx(xx_ix as format 'xxxx-xx') gff &jfjfsj_jfjfj.) and 
      (xxx(xx_ix as format 'xxxx-xx') lec &jgjsd_vnv.))(( ))
 );

2)(

RUN;

任何建议或解决此问题的不同方法将不胜感激!

执行用户@Finefoot 的代码后的输出:

但是,有没有办法将线条分开,使其看起来像这样?:

【问题讨论】:

考虑使用正则表达式 你忘记了re.DOTALL标志 【参考方案1】:

我认为,在您的模式中 (PROC SQL;|proc sql;(.*?)RUN;|quit;|QUIT;) 是一个错字,因为您在 proc sql; 之后和 (.*?) 之前缺少右括号 ) 以及之后的左括号 ( 。然而,这还不是全部,修正错字后,您仍然无法获得想要的结果。

查看re 的 Python 文档:

.(点)在默认模式下,它匹配除换行符以外的任何字符。如果指定了DOTALL 标志,则匹配任何字符,包括换行符。

由于您的输入确实包含您希望. 匹配的换行符,因此您需要使用re.DOTALL 标志。当我们讨论标志时:如果您真的不关心关键字是否区分大小写,您可能还想使用re.IGNORECASE 标志。

另外,我猜你不希望你的结果中出现像PROC SQL; 这样的关键字,所以你可以使用(?:...),这是常规括号的非捕获版本。

最终的正则表达式模式:

re.findall(r"(?:PROC SQL;)(.*?)(?:RUN;|QUIT;)", text, flags=re.IGNORECASE|re.DOTALL)

更新:

在上面 Jupyter 单元格中的更新代码中,re.findall 的结果保存为变量 regex。这是一个与模式匹配的字符串列表。如果您调用print(regex),您将打印列表(它将显示其元素,字符串,\n)。如果您不想要\n,您可以打印元素(字符串本身):print(*regex) 不过,两个元素之间的默认分隔符将是一个简单的空格字符,因此您可能希望将sep 设置为其他类似多个换行符print(*regex, sep="\n"*5)----- 的分隔线print(*regex, sep="\n"+"-"*44+"\n")。但这是您必须决定哪种方式最适合您展示您的结果。

此外,如果该模式看起来还不是太令人困惑,您可能希望使用“内联修饰符”而不是 flags 参数。 (?i:...) 用于不区分大小写的匹配,(?s:...) 而不是 DOTALL 标志:

re.findall(r"(?i:PROC SQL;)((?s:.*?))(?i:RUN;|QUIT;)", text)

【讨论】:

【参考方案2】:

这对我有用:

import re

with open('lan sample text file1.txt') as file:
    condition = False
    text_to_return = ""
    for line in file:
        if condition == True:
            if line[0:5].lower() == "quit;" or line[0:4].upper() == "RUN;":
                condition = False    
            text_to_return += line
        if line[0:9].upper() == "PROC SQL;":
            condition = True
            text_to_return += line

    output_file = open("output.txt", "w")
    output_file.write(text_to_return)
    output_file.close()

这是您可以接受的解决方案吗?

【讨论】:

你好 asymmetryFan,谢谢!我试过你的代码,它有效!虽然它可能不适用于我拥有的其他类似的 .txt 文件,这些文件不包含与您在代码中编写的行范围相同的开始和结束词。 @jackie 不客气,总是乐于助人! :) 我希望我的代码至少可以作为泛化多个文件的起点。【参考方案3】:

不想使用正则表达式的解决方案:

starts=["PROC SQL;"]
ends = ["RUN;", "RUN;", "QUIT;"]

with open('/tmp/some_file.txt') as f:
    content = f.read() 

    for s, e in zip(starts, ends):
        if s.lower() in content.lower() and e.lower() in content.lower():
            start = content.lower().find(s.lower())
            end = content.lower().find(e.lower()) + len(e)

            print(content[start:end])

对你有帮助吗?

【讨论】:

嘿菲利克斯,非常感谢您的代码,它可以工作:) 但是当我在我的工作桌面上尝试它时,我有多个文件要解析,不仅仅是一个,它似乎无法捕获包含关键字的所有内容,跨多个 .txt 文件。【参考方案4】:

通过匹配关键字可以获得更高效的匹配,匹配所有不以quitRUN开头的行,防止.*?引起不必要的回溯

如果您希望关键字包含在匹配中,您可以省略捕获组。

您可以使用re.IGNORECASE 标志来获得不区分大小写的匹配,并使用re.MULTILINE,因为该模式包含一个断言字符串开头的锚。

^PROC SQL;.*\n(?:(?!RUN;|QUIT;).*\n)*(?:RUN|QUIT);
^行首 PROC SQL; 字面上匹配 .*\n 匹配除换行符以外的任何字符 0+ 次,然后匹配换行符(或使用 \r?\n (?:非捕获组 (?!RUN;|QUIT;) 断言右边不是RUN;QUIT; .*\n 匹配除换行符以外的任何字符 0+ 次,然后匹配换行符 )*关闭组并重复0+次 (?:RUN|QUIT); 匹配 RUN;QUIT;

Regex demo | Python demo

例如

with open('lan sample text file1.txt') as file:
    text = file.read()
    regex = re.compile(r'^PROC SQL;.*\n(?:(?!RUN;|QUIT;).*\n)*(?:RUN|QUIT);', re.MULTILINE | re.IGNORECASE)
    k = regex.findall(text)
    print(k)

【讨论】:

谢谢,第四只鸟!您的代码有效:) 但我想它是特定于大小写的,只能应用于这个特定的 .txt 文件,而不适用于我的其他 .txt 文件,它们相似但在 .txt 中的关键字放置有所不同文件。

以上是关于提取 .txt 文件中两个关键字之间的所有单词的主要内容,如果未能解决你的问题,请参考以下文章

查找包含关键字和提取编号的所有行

使用pywin32从word文档中选择两个单词之间的文本

PHP RegEx 删除两个单词之间的双空格

如何用批处理提取一目录下所有文本文件中的特定字符并同文件名一起输出?

bat批处理提取txt关键词所在行并输出文件

java poi 提取txt文件内容添加到excel