Поиск и удаление указанной c строки текста в текстовом файле - PullRequest
0 голосов
/ 25 февраля 2020

Я хотел бы найти содержимое файла .txt для указанной строки текста c и удалить только эту строку из файла .txt.

Я хочу указать строку текст для поиска в качестве переменной. Например:

set lineOfTextToDelete to "The quick brown fox jumps over the lazy dog."

Содержимое до:

Допустим, содержимое моего TestDelta.txt файла:

This is a a paragraph of text.
This is another line of text.
The quick brown fox jumps over the lazy dog.
Here is another line

Содержание после:

Ниже показано содержимое TestDelta.txt, которое я хочу после запуска скрипта. Как вы можете видеть строку, которая была назначена переменной lineOfTextToDelete, т.е. "Быстрая коричневая лиса перепрыгивает через ленивую собаку." было удалено из содержимого файла.

This is a a paragraph of text.
This is another line of text.
Here is another line

Что я пробовал до сих пор:

Ниже приведено то, что я пробовал, однако я не уверен, что мне делать дальше?

set txtfile to "Macintosh HD - Data:Users:crelle:Desktop:TestDelta.txt" as alias
set thisone to read txtfile
set theTextList to paragraphs of thisone

Может кто-нибудь помочь показать мне, что делать?

1 Ответ

2 голосов
/ 29 февраля 2020

Вот, в произвольном порядке, пара решений для рассмотрения.

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

Если у вас есть какие-либо вопросы относительно назначения правильного пути к файлу либо;

  • Переменная txtFilePath в Решение A
  • Свойство txtFilePath в Решение B

затем замените одну из этих строк следующим. Это позволит вам выбрать файл .

set txtFilePath to (choose file)

Решение A: Оболочка из AppleScript и использование SED (Stream EDitor)

on removeMatchingLinesFromFile(findStr, filePath)
  set findStr to do shell script "sed 's/[^^]/[&]/g; s/\\^/\\\\^/g' <<<" & quoted form of findStr
  do shell script "sed -i '' '/^" & findStr & "$/d' " & quoted form of (POSIX path of filePath)
end removeMatchingLinesFromFile

set txtFilePath to "Macintosh HD - Data:Users:crelle:Desktop:TestDelta.txt"
set lineOfTextToDelete to "The quick brown fox jumps over the lazy dog."

removeMatchingLinesFromFile(lineOfTextToDelete, txtFilePath)

Объяснение:

  1. Произвольно названное removeMatchingLinesFromFile подпрограмма / функция содержит задачи, необходимые для удовлетворения ваших требований. В нем перечислены два параметра; findStr и filePath. В его теле мы "выкладываем" дважды до sh, используя команду AppleScript do shell script.

    Давайте разберемся, что здесь происходит более подробно:

    • Первая строка, которая читает;

      set findStr to do shell script "sed 's/[^^]/[&]/g; s/\\^/\\\\^/g' <<<" & quoted form of findStr
      

      выполняет команду sed. Цель этой команды - избежать любых потенциальных метасимволов Basi c Regular Expression (BRE) , которые могут существовать в данной строке текста, который мы хотим удалить. Абсолютно он гарантирует, что каждый символ в данной строке будет рассматриваться как литерал при использовании в последующей команде sed, что сводит на нет любое «специальное значение» , которое имеет метасимвол.

      См. этот ответ для дальнейшего объяснения. По сути, он выполняет следующие действия:

      • Каждый символ, кроме ^, помещается в собственный набор символов [...] выражение, чтобы рассматривать его как литерал.
        • Обратите внимание, что ^ - это один символ. Вы не можете представлять как [^], потому что оно имеет особое значение в этом месте (отрицание).
      • Затем ^ символов. экранируются как \^.
        • Обратите внимание, что вы не можете просто избежать каждого символа, поставив перед ним \, потому что это может превратить буквенный символ в мета-символ, например, \< и \b являются границами слов в некоторых инструментах, \n - это новая строка, \{ - начало интервала RE, например \{1,3\}, et c.

      Кредит для этого шаблона SED идет в Эд Мортон и mklement0 .

      Итак, учитывая, что строка присвоена переменной с именем lineOfTextToDelete is:

      The quick brown fox jumps over the lazy dog.
      

      в действительности мы назначаем следующую строку переменной findStr после ее анализа с помощью команды sed:

      [T][h][e][ ][q][u][i][c][k][ ][b][r][o][w][n][ ][f][o][x][ ][j][u][m][p][s][ ][o][v][e][r][ ][t][h][e][ ][l][a][z][y][ ][d][o][g][.]
      

      Как вы можете видеть, что каждый символ заключен в открывающие и закрывающие квадратные скобки, то есть [], чтобы сформировать серию скобочных выражений .

      Для дальнейшей демонстрации происходящего; запустите приложение Terminal и выполните следующую составную команду:

      sed 's/[^^]/[&]/g; s/\^/\\^/g' <<<"The quick brown fox jumps over the lazy dog."
      

      Примечание При запуске вышеупомянутой составной команды непосредственно через Terminal шаблон sed содержит меньше обратных косых черт (\) по сравнению с шаблоном, указанным в AppleScript. Это связано с тем, что для строк AppleScript требуется экранирование любой обратной косой черты sh с дополнительной обратной косой чертой sh.

    • чтение второй строки

      do shell script "sed -i '' '/^" & findStr & "$/d' " & quoted form of (POSIX path of filePath)
      

      выполняет другую команду sed через оболочку. Это выполняет задачу поиска всех экземпляров данной строки текста в файле и удаляет его / их.

      • Опция -i указывает, что файл должен редактироваться на месте и требует использования следующего пустого строкового аргумента ('') при использовании BSD версии sed, поставляемой с macOS.

      • Часть '/^" & findStr & "$/d' - это шаблон, который мы предоставляем sed.

        • Метасимвол ^ совпадает со строкой null в начале пространства шаблонов - это по сути означает начало соответствия последующему шаблону регулярных выражений, только если он существует в начале строки.

        • Переменная Applescript findStr - это результат, который мы получили с помощью предыдущей команды sed. Он объединяется с предыдущей частью шаблона с помощью оператора &.

        • Метасимвол $ относится к концу пространства шаблона, то есть к концу

        • d - это команда удаления.

        • В части & quoted form of (POSIX path of filePath) используется AppleScript POSIX path свойство для преобразования указанного вами пути HFS , то есть

          Macintosh HD - Data:Users:crelle:Desktop:TestDelta.txt
          

          в следующий стиль POSIX путь:

          /Macintosh HD - Data/Users/crelle/Desktop/TestDelta.txt
          

          Свойство quoted form обеспечивает правильное цитирование пути в стиле POSIX *1209*. Например, он гарантирует, что любые пробельные символы в указанном пути правильно интерпретируются оболочкой.

      Опять же, чтобы дополнительно продемонстрировать, что происходит; запустите приложение Terminal и выполните следующую составную команду:

      sed -i '' '/^[T][h][e][ ][q][u][i][c][k][ ][b][r][o][w][n][ ][f][o][x][ ][j][u][m][p][s][ ][o][v][e][r][ ][t][h][e][ ][l][a][z][y][ ][d][o][g][.]$/d' ~/Desktop/TestDelta.txt
      
  2. Давайте разберемся, как использовать вышеупомянутую функцию removeMatchingLinesFromFile:

    • Сначала мы назначим тот же путь HFS, который вы указали в своем вопросе, переменной с произвольным именем txtFilePath:

      set txtFilePath to "Macintosh HD - Data:Users:crelle:Desktop:TestDelta.txt"
      
    • Далее мы присваиваем строку текста, которую мы хотим найти и удалить, переменной с произвольным именем lineOfTextToDelete:

      set lineOfTextToDelete to "The quick brown fox jumps over the lazy dog."
      
    • Наконец мы вызываем пользовательскую функцию removeMatchingLinesFromFile, передавая два обязательные аргументы а именно; lineOfTextToDelete и txtFilePath:

      removeMatchingLinesFromFile(lineOfTextToDelete, txtFilePath)
      

Решение B: Использование ванильного AppleScript без SED:

Это решение предоставлено ниже не используются ни оболочка, ни SED, но и тот же желаемый результат, что и для Решение A .

property lineOfTextToDelete : "The quick brown fox jumps over the lazy dog."
property txtFilePath : alias "Macintosh HD - Data:Users:crelle:Desktop:TestDelta.txt"

removeMatchingLinesFromFile(lineOfTextToDelete, txtFilePath)


on removeMatchingLinesFromFile(findStr, filePath)
  set paraList to {}
  repeat with aLine in getLinesFromFile(filePath)
    if contents of aLine is not findStr then set paraList to paraList & aLine
  end repeat
  set newContent to transformListToText(paraList, "\n")
  replaceFileContents(newContent, filePath)
end removeMatchingLinesFromFile


on getLinesFromFile(filePath)
  if (get eof of filePath) is 0 then return {}
  try
    set paraList to paragraphs of (read filePath)
  on error errorMssg number errorNumber
    error errorMssg & errorNumber & ": " & POSIX path of filePath
  end try
  return paraList
end getLinesFromFile


on transformListToText(ListOfStrings, delimiter)
  set {tids, text item delimiters} to {text item delimiters, delimiter}
  set content to ListOfStrings as string
  set text item delimiters to tids
  return content
end transformListToText


on replaceFileContents(content, filePath)
  try
    set readableFile to open for access filePath with write permission
    set eof of readableFile to 0
    write content to readableFile starting at eof
    close access readableFile
    return true
  on error errorMssg number errorNumber
    try
      close access filePath
    end try
    error errorMssg & errorNumber & ": " & POSIX path of filePath
  end try
end replaceFileContents

Объяснение:

Я оставлю это объяснение Короче говоря, сам код , вероятно, проще для понимания, чем Решение A .

Подпрограмма removeMatchingLinesFromFile, по существу, выполняет следующее с помощью дополнительных вспомогательных функций:

  1. read - содержимое данного файла .txt с помощью функции getLinesFromFile и return sa список . Каждый элемент в возвращенном списке содержит каждую строку / абзац текста, найденного в содержимом файла .txt.

  2. Затем мы пропускаем oop через каждый элемент (т.е. каждую строку текста) через оператор repeat. Если contents каждого элемента не не совпадает с заданной строкой текста, мы находим ее в другом списке, то есть в списке, назначенном переменной paraList.

  3. Затем список, назначенный переменной paraList, передается в функцию transformListToText вместе с разделителем новой строки (\n). Функция transformListToText возвращает новую строку.

  4. Наконец, с помощью функции replaceFileContents мы open for access исходный файл .txt и более write его содержимое с новым содержимым.


Важное примечание, применимое к любому решению: При указании строка текста, которую вы хотите удалить (т. е. строка, назначенная переменной lineOfTextToDelete), гарантирует, что все и вся backsla sh \, которые вы можете найти, экранированы с другим. Например; если строка, которую вы хотите найти, содержит единственную обратную косую черту sh \, тогда экранируйте ее, чтобы стать двумя \\. Точно так же, если строка, которую вы хотите найти, содержит две последовательные обратные косые черты \\, тогда экранируйте каждую из них, чтобы стать четырьмя \\\\ и т. Д.


Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...