знайти певний рядок і видалити всю структуру


3

У мене є вертикальний файл, де кожне слово (маркер) знаходиться в окремому рядку в 4 стовпцях. Там також метаструктур <doc>, <s>... Документи виглядають наступним чином :

<doc name="sth" url="http">
<p>
<s>
Here   here   k1gInSc1   here
is   be   k1gMnPc2   be
a  a   k2eAgMnPc1d1   a
sentence   sentence   k1gMnPc1   sentence
<g/>
.       .       kIx.
</s>
</p>
</doc>

проблема полягає в тому, що іноді в першому стовпчику неправильне кодування з символами як Ă або Ä , наприклад

<doc name="sth" url="http">
<p>
<s>
Here   here   k1gInSc1   here
is   be   k1gMnPc2   be
Ă  Ă   k?   Ă
sentence   sentence   k1gMnPc1   sentence
<g/>
.       .       kIx.
</s>
</p>
</doc>

Мені потрібно було б знайти цих символів і видалити всю структуру документа. Отже, якщо я знайду Ă на рядку, мені потрібно видалити весь вміст між <doc...>усіма рядками </doc>.

У моєму файлі є мільярд рядків і приблизно кілька тисяч рядків містять неправильно закодовані символи.

Я використовував греп для пошуку поганих символів:

xzcat file.vert.xz | grep -i "Ă\|Ĺ\|ľ\|ş\|Ä" > file_bad_characters.txt

Як я можу виявити ці символи та видалити не лише рядок, а й весь текст між <doc>структурами.


Дякуємо за поради. Нарешті, мені вдалося вирішити проблему з поганим кодуванням, тому видаляти їх не довелося.
Родріго

Відповіді:


2

Правильний спосіб зробити це - використовувати правильний XML-аналізатор. Однак у цьому випадку можливе наступне:

  1. Видаліть із файлу всі порожні рядки:

    sed -i '/^\s*$/d' file
    
  2. Додайте порожній рядок перед кожним <doc>:

    sed -i 's/<doc/\n\n<doc/' file 
    
  3. Користувач Perl в "абзацному режимі", де "рядки" визначаються як "абзаци" (розділи тексту, які передують порожньому рядку):

    perl -00 -ne 'print unless /[ĂĹľşÄ]/' file > newfile
    

    Або заміни в оригінальному файлі:

    perl -i.bak -00 -ne 'print unless /[ĂĹľşÄ]/' file
    

ВАЖЛИВО : Це передбачає добре структурований файл, де все знаходиться в <doc...тегах.


2

Боюся, це не те, що ти можеш зробити з просто грепом; для цього потрібно зберегти деякий контекст щодо рядків, які не може надати греп. Однак є кілька інших мов, які можуть це зробити; ось приклад із awk:

awk '/<doc>/ {text=""; output=1}
     /Ă|Ĺ|ľ|ş|Ä/{output=0}
     {text = text $0 "\n"}
     /<\/doc>/ {if(output==1){printf "%s", text}}"

Це створює буфер, який називається, textколи ми бачимо маркер <doc>на вході, і встановлює прапор для сигналу про те, що ми хочемо бачити текст друкованим; цей прапор видаляється, коли зустрічаються заборонені символи. Коли ми зустрічаємо маркер </doc>, ми перевіряємо, чи прапор все-таки встановлений; якщо так, ми відображаємо буфер. Нарешті, кожен рядок додається до нашого буфера, незалежно від того, встановлений прапор чи ні.


Це працює, і я використовував його багато разів. Дякую!
Родріго
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.