Cách xóa JavaScript và các thẻ khác bằng Python… mà không cần nhập mô-đun

Sep 30 2020

Đối với phần đầu tiên của dự án trường học, tôi đang cố gắng tìm ra cách xóa JavaScript <script {...} >và </script {...} >thẻ cũng như bất kỳ thứ gì giữa <và >.

Tuy nhiên, chúng tôi không thể nhập bất kỳ mô-đun nào (ngay cả những mô-đun được xây dựng bằng Python) vì rõ ràng điểm đánh dấu có thể không thể truy cập chúng, v.v.

Tôi đã thử điều này:

text = "<script beep beep> hello </script boop doop woop> hello <hi> hey <bye>"
while text.find("<script") >= 0:
    script_start = text.find("<script")
    script_end = text.find(">", text.find("</script")) + 1
    text = text[:script_start] + text[script_end:]

while text.find("<") >= 0:
    script2_start = text.find("<")
    script2_end = text.find(">") + 1
    text = text[:script2_start] + text[script2_end:]

Và điều đó có hiệu quả với các tệp nhỏ hơn nhưng dự án phải làm với các tệp văn bản lớn (thử nghiệm đơn giản mà chúng tôi đưa ra là 10,4MB) nên nó không hoàn thành và nó chỉ bị kẹt.

Bất cứ ai có bất kỳ ý tưởng để làm cho nó hiệu quả hơn?

Trả lời

2 PatrickArtner Sep 30 2020 at 17:33

Bạn không cần phải xóa bất cứ thứ gì. Trên thực tế: bạn không bao giờ muốn sửa đổi chuỗi.

Chuỗi là không thể thay đổi: mỗi khi bạn "sửa đổi" một chuỗi, thay vào đó bạn tạo một chuỗi mới và bỏ đi cái cũ. Điều đó gây lãng phí bộ xử lý và bộ nhớ.

Bạn đang thao tác trên các tệp - vì vậy hãy xử lý theo ký tự:

  • nhớ xem bạn có ở trong nhà <...>hay không
  • nếu vậy, chỉ có nhân vật quan trọng là >quay lại bên ngoài
  • nếu bên ngoài và nhân vật là <bạn vào bên trong và bỏ qua nhân vật đó
  • nếu bên ngoài và không <bạn ghi ký tự vào đầu ra (-tệp)

# create file
with open("somefile.txt","w") as f:
    # up the multiplicator to 10000000 to create something in the megabyte range
    f.write("<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata\n"*10)

# open file to read from and file to write to
with open("somefile.txt") as f, open("otherfile.txt","w") as out:
    # starting outside
    inside = False
    # we iterate the file line by line
    for line in f:
        # and each line characterwise
        for c in line:
            if not inside and c == "<":
                inside = True
            elif inside and c != ">":
                continue
            elif inside and c == ">":
                inside = False
            elif not inside:
                # only case to write to out
                out.write(c)

print(open("somefile.txt").read() + "\n")
print(open("otherfile.txt").read())

Đầu ra:

<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata
<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata
<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata
<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata
<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata
<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata
<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata
<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata
<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata
<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata


 hello  hello  hey  tata
 hello  hello  hey  tata
 hello  hello  hey  tata
 hello  hello  hey  tata
 hello  hello  hey  tata
 hello  hello  hey  tata
 hello  hello  hey  tata
 hello  hello  hey  tata
 hello  hello  hey  tata
 hello  hello  hey  tata

Nếu bạn không được phép thao tác trực tiếp với tệp, hãy đọc tệp đó vào danh sách sử dụng 11+ Mbyte bộ nhớ:

data = list("<script beep beep> hello </script boop doop woop> hello <hi> hey <bye> tata\n" * 10)

result = []

inside = False
for c in data:
    if inside:
        if c == ">":
            inside = False
        # else ignore c - because we are inside
    elif c == "<":
        inside = True
    else:
        result.append(c)

print(''.join(result))

điều này vẫn tốt hơn sau đó tìm kiếm lặp đi lặp lại lần xuất hiện đầu tiên của "<" trong danh sách nhưng có thể cần đến gấp đôi bộ nhớ nguồn của bạn (nếu nó không chứa bất kỳ <..> bạn nhân đôi danh sách).

Việc vận hành các tệp sẽ hiệu quả hơn nhiều về bộ nhớ sau đó thực hiện bất kỳ sửa đổi danh sách tại chỗ nào (đây sẽ là cách thứ ba để làm điều này).


Có một số thứ chói mắt bạn cũng cần phải giải quyết, fe

<script type="text/javascript">
var i = 10;
if (i < 5) {
  // some code
}
</script>

sẽ để lại "mã" bên trong.


Điều này có thể thực hiện các trường hợp góc dễ dàng hơn:

# open file to read from and file to write to
with open("somefile.txt") as f, open("otherfile.txt","w") as out:
    # starting outside
    inside = False
    insideJS = False
    jsStart = 0
    # we iterate the file line by line
    for line in f:

        # string manipulation :/ - will remove <script ...> .. </script ..>
        # even over multiple lines - probably missed some cornercases.
        while True:
          if insideJS and not "</script" in line:
              line = ""
              break

          if "<script" in line:
              insideJS = True
              jsStart = line.index("<script")
              jsEnd = len(line)
          elif insideJS:
              jsStart = 0
          
          if not insideJS:
              break

          if "</script" in line:
              jsEnd = line.index(">", line.index("</script", jsStart))+1
              line = line[:jsStart] + line[jsEnd:]
              insideJS = False
          else:
              line = line[:jsStart]

        # and each line characterwise
        for c in line:
            # ... same as above ...
1 woblob Sep 30 2020 at 18:18

Mặc dù có 2 vòng lặp while, nó vẫn là độ phức tạp tuyến tính

string = "<script beep beep> hello </script boop doop woop> hello <hi> hey <bye>"
new_string = ''
i = 0
while i < len(string):
    if string[i] == "<":
        while i < len(string):
            i += 1
            if string[i] == '>':
                break
    else:
        new_string += string[i]
    i += 1

print(new_string)

Kết quả đầu ra:

 hello  hello  hey 
1 Tibebes.M Sep 30 2020 at 17:49

Đây là một cách tiếp cận với FSA :

output = ''

NORMAL, INSIDE_TAG = range(2) # availale states

state = NORMAL # start with normal state

s = '<script beep beep> hello </script boop doop woop> hello <hi id="someid" class="some class"><a> hey </a><bye>'

for char in s:
  if char == '<': # if we encounter '<' we enter the INSIDE_TAG state
    state = INSIDE_TAG
    continue
  elif char == '>': # we can safely exit the INSIDE_TAG state
    state = NORMAL
    continue

  if state == NORMAL:
    output += char  # add the char to the output only if we are in normal state

print(output)

Nếu phân tích ngữ nghĩa các thẻ là bắt buộc, hãy đảm bảo sử dụng ngăn xếp (có thể được triển khai với list).


Nó sẽ làm tăng độ phức tạp nhưng bạn sẽ đạt được sự kiểm tra mạnh mẽ với FSM.

xem ví dụ sau:

output = ''

(
  NORMAL,
  TAG_ATTRIBUTE,
  INSIDE_JAVASCRIPT,
  EXITING_TAG,
  BEFORE_TAG_OPENING_OR_ENDING,
  TAG_NAME,
  ABOUT_TO_EXIT_JS
) = range(7) # availale states

state = NORMAL # start with normal state

tag_name = ''

s = """
<script type="text/javascript">
  var i = 10;
  if (i < 5) {
    // some code
  }
</script>
<sometag>
  test string
  <a href="http://google.com"> another string</a>
</sometag>
"""

for char in s:
  # print(char, '-', state, ':', tag_name)
  if state == NORMAL:
    if char == '<':
      state = BEFORE_TAG_OPENING_OR_ENDING
    else:
      output += char
  elif state == BEFORE_TAG_OPENING_OR_ENDING:
    if char == '/':
      state = EXITING_TAG
    else:
      tag_name += char
      state = TAG_NAME
  elif state == TAG_ATTRIBUTE:
    if char == '>':
      if tag_name == 'script':
        state = INSIDE_JAVASCRIPT
      else:
        state = NORMAL
  elif state == TAG_NAME:
    if char == ' ':
      state = TAG_ATTRIBUTE
    elif char == '>':
      if tag_name == 'script':
        state = INSIDE_JAVASCRIPT
      else:
        state = NORMAL
    else:
      tag_name += char
  elif state == INSIDE_JAVASCRIPT:
    if char == '<':
      state = ABOUT_TO_EXIT_JS
    else:
      pass
      # output += char
  elif state == ABOUT_TO_EXIT_JS:
    if char == '/':
      state = EXITING_TAG
      tag_name = ''
    else:
      # output += '<'
      state = INSIDE_JAVASCRIPT
  elif state == EXITING_TAG:
    if char == '>':
      state = NORMAL

print(output)

ĐẦU RA:

  test string
  another string