Извлечь все слова между двумя ключевыми словами в файл .txt - PullRequest
4 голосов
/ 11 декабря 2019

Я хотел бы извлечь все слова из определенных ключевых слов в текстовом файле. Для ключевых слов есть начальное ключевое слово PROC SQL; (мне нужно, чтобы оно не учитывало регистр), а конечное ключевое слово может быть либо RUN;, quit;, либо QUIT;. Это мой образец .txt файл .

Пока что это мой код:

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: enter image description here

Однако есть ли способ разделить строки, чтобы они выглядели примерно так?

enter image description here

Ответы [ 4 ]

2 голосов
/ 11 декабря 2019

Решение, если вы не хотите использовать регулярные выражения:

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

Помогает ли это вам?

1 голос
/ 11 декабря 2019

Вы можете получить более эффективное соответствие, сопоставляя ключевые слова и сопоставляя все строки, которые не начинаются с quit или RUN, чтобы предотвратить ненужный откат, вызванный .*?

Если вы хотитеключевые слова, включенные в совпадение, вы можете опустить группы захвата.

Вы можете использовать флаг 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)
1 голос
/ 11 декабря 2019

Это работает для меня:

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

Это приемлемое для вас решение?

1 голос
/ 11 декабря 2019

В вашем паттерне (PROC SQL;|proc sql;(.*?)RUN;|quit;|QUIT;) - это опечатка, я думаю, так как вам не хватает закрывающей скобки ) после proc sql; и до (.*?), а также открывающей скобки ( после. Однако это еще не все, вы все равно не получите желаемый результат с исправленной опечаткой.

Посмотрите документы Python для re:

. (Точка). В режиме по умолчанию это соответствует любому символу, кроме новой строки. Если был указан флаг 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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...