Python убрать квадратные скобки и лишнюю информацию между ними - PullRequest
11 голосов
/ 06 мая 2020

Я пытаюсь обработать файл, и мне нужно удалить из файла постороннюю информацию; в частности, я пытаюсь удалить скобки [], включая текст внутри и между блоками скобок [] [], говоря, что все между этими блоками, включая их самих, но печатает все, что находится за его пределами.

Ниже мой текстовый файл с образцом данных:

$ cat smb
Hi this is my config file.
Please dont delete it

[homes]
  browseable                     = No
  comment                        = Your Home
  create mode                    = 0640
  csc policy                     = disable
  directory mask                 = 0750
  public                         = No
  writeable                      = Yes

[proj]
  browseable                     = Yes
  comment                        = Project directories
  csc policy                     = disable
  path                           = /proj
  public                         = No
  writeable                      = Yes

[]

This last second line.
End of the line.

Желаемый результат:

Hi this is my config file.
Please dont delete it
This last second line.
End of the line.

Что я пробовал, основываясь на моем понимании и повторном поиске:

$ cat test.py
with open("smb", "r") as file:
  for line in file:
    start = line.find( '[' )
    end = line.find( ']' )
    if start != -1 and end != -1:
      result = line[start+1:end]
      print(result)

Вывод:

$ ./test.py
   homes
   proj

Ответы [ 12 ]

7 голосов
/ 08 мая 2020

с одним регулярным выражением

import re

with open("smb", "r") as f: 
    txt = f.read()
    txt = re.sub(r'(\n\[)(.*?)(\[]\n)', '', txt, flags=re.DOTALL)

print(txt)

объяснение регулярного выражения:

(\n\[) найти последовательность, в которой есть разрыв строки, за которой следует [

(\[]\n) найти последовательность, где есть [], за которым следует разрыв строки

(.*?) удалить все, что находится в середине (\n\[), а (\[]\n)

re.DOTALL используется для предотвращения ненужного возврата


!!! PANDAS ОБНОВЛЕНИЕ !!!

То же решение с тем же logi c может быть выполнено с pandas

import re
import pandas as pd

# read each line in the file (one raw -> one line)
txt = pd.read_csv('smb',  sep = '\n', header=None)
# join all the line in the file separating them with '\n'
txt = '\n'.join(txt[0].to_list())
# apply the regex to clean the text (the same as above)
txt = re.sub(r'(\n\[)(.*?)(\[]\n)', '\n', txt, flags=re.DOTALL)

print(txt)
5 голосов
/ 06 мая 2020

Прочтите файл в строку,

extract = '''Hi this is my config file.
Please dont delete it

[homes]
  browseable                     = No
  comment                        = Your Home
  create mode                    = 0640
  csc policy                     = disable
  directory mask                 = 0750
  public                         = No
  writeable                      = Yes

[proj]
  browseable                     = Yes
  comment                        = Project directories
  csc policy                     = disable
  path                           = /proj
  public                         = No
  writeable                      = Yes

[]

This last second line.
End of the line.
'''.split('\n[')[0][:-1]

даст вам,

Hi this is my config file.
Please dont delete it

.split('\n[') разбивает строку по вхождению '\n[' набора символов и [0] выбирает верхние строки описания.

with open("smb", "r") as f: 
     extract = f.read()
     tail = extract.split(']\n')
     extract = extract.split('\n[')[0][:-1]+[tail[len(tail)-1]

будет читать и выводить,

Hi this is my config file.
Please dont delete it
This last second line.
End of the line.
4 голосов
/ 09 мая 2020

Поскольку вы отметили pandas, давайте попробуем следующее:

df = pd.read_csv('smb', sep='----', header=None)

# mark rows starts with `[`
s = df[0].str.startswith('[')

# drop the lines between `[`
df = df.drop(np.arange(s.idxmax(),s[::-1].idxmax()+1))

# write to file if needed
df.to_csv('clean.txt', header=None, index=None)

Вывод (df):

                             0
0   Hi this is my config file.
1        Please dont delete it
18      This last second line.
19            End of the line.
3 голосов
/ 14 мая 2020

Использование Pandas:

df = pd.read_csv('smb.txt', sep='----', header=None, engine='python',names=["text"])

res = df.loc[~df.text.str.contains("=|\[.*\]")]
print(res)
text
0   Hi this is my config file.
1   Please dont delete it
18  This last second line.
19  End of the line.

Пояснение : Исключить строки, содержащие либо =, либо начальную скобку ([), за которыми можно следовать или не следовать символами (.*) и закрывающей скобкой (]``). the backslash ( `` '') указывает python не обрабатывать скобки как специальные символы

Только с Python используется тот же шаблон регулярного выражения , с дополнительной строкой для пустых записей:

import re
with open('smb.txt') as myfile:
    content = myfile.readlines()
    pattern = re.compile("=|\[.*\]")
    res = [ent.strip() for ent in content if not pattern.search(ent) ]
    res = [ent for ent in res if ent != ""]
    print(res)
['Hi this is my config file.',
 'Please dont delete it',
 'This last second line.', 
 'End of the line.']
3 голосов
/ 13 мая 2020

Вы ошиблись при индексации. В остальном код вроде в порядке.

Попробуйте:

start=0
targ = ""
end=0
with open("smb", "r") as file:
    for line in file: 
        try:  
            if start==0:
                start = line.index("[")
        except:
            start = start
        try:  
            end = line.index("]")
        except:
            end = end
        targ = targ+line

targ = targ[0:start-1]+targ[end+1:]

Это должно сработать. Дай мне знать, если что-то пойдет не так. :)

3 голосов
/ 13 мая 2020

Поскольку вы отметили pandas и указали, что текст стоит до и после квадратных скобок, мы можем использовать str.contains и использовать логическое значение для фильтрации строк, которые попадают между первой и последней квадратными скобками.

df = pd.read_csv(your_file,sep='\t',header=None)

idx = df[df[0].str.contains('\[')].index

df1 = df.loc[~df.index.isin(range(idx[0],idx[-1] + 1))]

                             0
0   Hi this is my config file.
1        Please dont delete it
18      This last second line.
19            End of the line.
3 голосов
/ 13 мая 2020

На Regex101 вы можете проверить это:

(^\W)+?\[[\w\W]+?\[\](\W)+?(\w)

В коде это похоже на

import re ------------------------------------------------------------↧-string where to replace-- result = re.sub(r"(^\W)+?\[[\w\W]+?\[\](\W)+?(\w)", "", input_string, 0, re.MULTILINE) ----------------------↑-this is the regex------------↑-substitution string-------------

Ура

3 голосов
/ 10 мая 2020

Другой вариант - сначала сопоставить квадратные скобки, такие как [homes], а затем сопоставить все строки, которые не только содержат [], поскольку это конечный маркер.

Вы можете получить совпадение без использования (?s) или используя re.DOTALL, чтобы предотвратить ненужный возврат и заменить совпадение пустой строкой.

^\s*\[[^][]*\](?:\r?\n(?![^\S\r\n]*\[]$).*)*\r?\n[^\S\r\n]*\[]$\s*

Пояснение

  • ^ Начало строки
  • \s* Соответствует 0+ пробелов
  • \[[^][]*\]
  • (?: Группа без захвата
    • \r?\n Соответствует новой строке
    • (?! Отрицательный просмотр вперед, утверждение, что то, что находится справа, не
      • [^\S\r\n]*\[]$ соответствует 0+ раз пробелам, кроме символов новой строки, и соответствует []
    • ) Закрыть группу без захвата
    • .* Сопоставить 0+ раз любой символ, кроме новой строки
  • )* Закрыть группу без захвата и повторить 0+ раз
  • \r?\n Соответствует новой строке
  • [^\S\r\n]* Соответствует 0+ пробелам без новой строки
  • \[]$ Мат ch [] и подтвердите конец строки
  • \s* Сопоставьте 0+ пробельных символов

Regex demo | Python демонстрация

Пример кода

import re

regex = r"^\s*\[[^][]*\](?:\r?\n(?![^\S\r\n]*\[]$).*)*\r?\n[^\S\r\n]*\[]$\s*"

with open("smb", "r") as file:
    data = file.read()
    result = re.sub(regex, "", data, 0, re.MULTILINE)
    print(result)

Вывод

Hi this is my config file.
Please dont delete it
This last second line.
End of the line.
3 голосов
/ 09 мая 2020

Если я вас правильно понял, вам нужно все до первого [ и после последнего ]. Если это не так, дайте мне знать, и я изменю свой ответ.

with open("smb", "r") as f: 
    s = f.read()
    head = s[:s.find('[')]
    tail = s[s.rfind(']') + 1:]
    return head.strip("\n") + "\n" + tail.strip("\n") # removing \n

Это даст вам желаемый результат.

3 голосов
/ 06 мая 2020

Вы можете перебирать строки файла и собирать их в некоторый список, если не достигнете строки, заключенной в скобки, а затем объедините собранные строки обратно:

with open("smb", "r") as f:
    result = []
    for line in f:
        if line.startswith("[") and line.endswith("]"):
            break
        result.append(line)
    result = "\n".join(result)
    print(result)
...