Удалить тег HTML, связанный с классом

Я заставляю себя научиться писать сценарии исключительно в AppleScript, но в настоящее время я сталкиваюсь с проблемой при попытке удалить определенный тег с помощью класса. Я пытался найти надежную документацию и примеры, но в настоящее время она кажется очень ограниченной.

Вот HTML-код, который у меня есть:

<p>Bacon ipsum dolor amet pork chop landjaeger short ribs boudin short loin jowl <span class="foo">shoulder</span> biltong shankle capicola drumstick pork loin rump spare ribs ham hock. <span class="bar">Pig brisket</span> jowl ham pastrami <span class="foo">jerky</span> strip steak bacon doner. Short loin leberkas jowl, filet mignon turducken chicken ribeye shank tail swine strip steak pork loin sausage. Frankfurter ground round porchetta, pork short ribs jowl alcatra flank sausage.</p>

То, что я пытаюсь сделать, это удалить определенный класс, чтобы он удалил <span class="foo">, результат:

<p>Bacon ipsum dolor amet pork chop landjaeger short ribs boudin short loin jowl shoulder biltong shankle capicola drumstick pork loin rump spare ribs ham hock. <span class="bar">Pig brisket</span> jowl ham pastrami jerky strip steak bacon doner. Short loin leberkas jowl, filet mignon turducken chicken ribeye shank tail swine strip steak pork loin sausage. Frankfurter ground round porchetta, pork short ribs jowl alcatra flank sausage.</p>

Я знаю как это сделать с do shell script и через терминал, но я хочу узнать, что доступно через словарь AppleScript.

В ходе исследования мне удалось найти способ для анализа всех тегов HTML с помощью:

on removeMarkupFromText(theText)
    set tagDetected to false
    set theCleanText to ""
    repeat with a from 1 to length of theText
        set theCurrentCharacter to character a of theText
        if theCurrentCharacter is "<" then
            set tagDetected to true
        else if theCurrentCharacter is ">" then
            set tagDetected to false
        else if tagDetected is false then
            set theCleanText to theCleanText & theCurrentCharacter as string
        end if
    end repeat
    return theCleanText
end removeMarkupFromText

но это удаляет все теги HTML, и это не то, что я хочу. Ища SO, я смог найти, как извлечь теги из исходного кода HTML с помощью AppleScript, но я не собираюсь анализировать файл.

Я знаком с BBEdit's Balance Tags известный как Balance в выпадающем списке, но когда я бегу:

tell application "BBEdit"
    activate
    find "<span class=\"foo\">" searching in text 1 of text document "test.html" options {search mode:grep, wrap around:true} with selecting match
    balance tags
end tell

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

Дальнейшие исследования в словаре под tag Я столкнулся find tag что я мог сделать: set spanTarget to (find tag "span" start_offset counter) затем нацелить тег с классом |class| of attributes of tag of spanTarget и использовать balance tags но я все еще сталкиваюсь с той же проблемой, что и раньше.

Так в чистом AppleScript, как я могу удалить тег, связанный с классом, не будучи жадным?

3 ответа

Решение

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

on run
    set theHTML to "<p>Bacon ipsum dolor amet pork chop landjaeger short ribs boudin short loin jowl <span class=\"foo\">shoulder</span> biltong shankle capicola drumstick pork loin rump spare ribs ham hock. <span class=\"bar\">Pig brisket</span> jowl ham pastrami <span class=\"foo\">jerky</span> strip steak bacon doner. Short loin leberkas jowl, filet mignon turducken chicken ribeye shank tail swine strip steak pork loin sausage. Frankfurter ground round porchetta, pork short ribs jowl alcatra flank sausage.</p>" 
    set theHTML to removeTag(theHTML, "<span class=\"foo\">", "</span>")
end run

on removeTag(theText, startTag, endTag)
    if theText contains startTag then
        set AppleScript's text item delimiters to {""}
        set AppleScript's text item delimiters to startTag
        set tempText to text items of (theText as string)
        set AppleScript's text item delimiters to {""}

        set middleText to item 2 of tempText as string
        if middleText contains endTag then
            set AppleScript's text item delimiters to endTag
            set tempText2 to text items of (middleText as string)
            set AppleScript's text item delimiters to {""}
            set newString to implode(tempText2, endTag)
            set item 2 of tempText to newString
        end if
        set newString to implode(tempText, startTag)
        removeTag(newString, startTag, endTag) -- recursive
    else
        return theText
    end if
end removeTag

on implode(parts, tag)
    set newString to items 1 thru 2 of parts as string
    if (count of parts) > 2 then
        set newList to {newString, items 3 thru -1 of parts}
        set AppleScript's text item delimiters to tag
        set newString to (newList as string)
        set AppleScript's text item delimiters to {""}
    end if
    return newString
end implode

Вы можете использовать регулярное выражение в find команда для BBEdit или TextWrangler:

Чтобы выбрать тег (Non-Greedy), используйте эту команду:

find "<span class=\"foo\">.+?</span>" searching in text 1 of text document 1 options {search mode:grep, wrap around:true} with selecting match

Информация от .+?</span> шаблон:

  • . соответствует любому символу (кроме разрыва строки)
  • + означает одно или несколько повторений любого символа
  • ? означает не жадные квантификаторы
  • Таким образом, шаблон соответствует открытию span тег, за которым следует одно или несколько вхождений любого символа, кроме возврата, с последующим закрытием span тег, не жадный квантификатор достигает желаемых результатов, не давая BBEdit обойти закрытие </span> тег и сопоставление нескольких тегов.

Чтобы соответствовать шаблону через разрывы строк, просто поместите (?s) в начале шаблона, вот так:

find "(?s)<span class=\"foo\">.+?</span>" searching in text 1 of text document 1 options {search mode:grep, wrap around:true} with selecting match

  1. Команда соответствует тегу без перевода строки:

<span class="foo">shoulder</span>

  1. Или команда сопоставляет тег с разрывом строки:

<span class="foo">shoulder </span>

  1. Или команда сопоставляет тег с несколькими строками:

<span class="foo">shoulder xxxx yyyy zzzz</span>


В AppleScript вы можете использовать команду замены (BBEdit или TextWrangler), чтобы найти шаблон и удалить все совпадающие строки, как это

replace "(?s)<span class=\"foo\">.+?</span>" using "" searching in text 1 of text document 1 options {search mode:grep, wrap around:true}

Это работа для регулярных выражений, которые доступны через использование поддерживаемого в настоящее время моста AppleScriptObjC. Вставьте этот код в Script Editor и запустите его:

use AppleScript version "2.5" -- for El Capitan or later
use framework "Foundation"
use scripting additions

on stringByMatching:thePattern inString:theString replacingWith:theTemplate
    set theNSString to current application's NSString's stringWithString:theString
    set theOptions to (current application's NSRegularExpressionDotMatchesLineSeparators as integer) + (current application's NSRegularExpressionAnchorsMatchLines as integer)
    set theExpression to current application's NSRegularExpression's regularExpressionWithPattern:thePattern options:theOptions |error|:(missing value)
    set theResult to theExpression's stringByReplacingMatchesInString:theNSString options:theOptions range:{location:0, |length|:theNSString's |length|()} withTemplate:theTemplate
    return theResult as text
end stringByMatching:inString:replacingWith:

set theHTML to "<p>Bacon ipsum dolor amet pork chop landjaeger short ribs boudin short loin jowl <span class='foo'>SHOULDER</span> biltong shankle capicola drumstick pork loin rump spare ribs ham hock. <span class='bar'>PIG BRISKET</span> jowl ham pastrami <span class='foo'>JERKY</span> strip steak bacon doner. Short loin leberkas jowl, filet mignon turducken chicken ribeye shank tail swine strip steak pork loin sausage. Frankfurter ground round porchetta, pork short ribs jowl alcatra flank sausage.</p>"

set modifiedHTML to its stringByMatching:"<span .*?>(.*?)</span>" inString:theHTML replacingWith:"$1"

Это работает с хорошо отформатированным HTML, но, как указал пользователь foo выше, браузер может работать с плохо отформатированным HTML, но вы, вероятно, не можете.

Другие вопросы по тегам