Сценарий оболочки UNIX/Linux: удаление эмодзи в форме варианта из текста

Предположим, вы используете оболочку Linux/UNIX, набор символов по умолчанию которой — UTF-8:

$ echo $LANG
en_US.UTF-8

У вас есть текстовый файл emoji.txt, закодированный в UTF-8:

$ file -i ./emoji.txt
./emoji.txt: text/plain; charset=utf-8

Этот текстовый файл содержит несколько эмодзи и альтернативную escape-последовательность:

$ cat     ./emoji.txt
Standard ☁
Variant form ☁️
$ uni2ascii -a B -q ./emoji.txt
Standard \x2601
Variant form \x2601\xFE0F

Вы хотите удалить оба смайлика, включая этот вариант символа формы (\ xFE0F), поэтому вывод должен быть

Standard 
Variant form 

Как бы вы это сделали?

Обновить. Этот вопрос не о том, как удалить последнее слово в каждой строке. Представьте себе файл emoji2.txt, который включает в себя большой текст с множеством символов эмодзи; и за некоторыми из них следует последовательность вариантов формы.


person Culip    schedule 10.08.2020    source источник
comment
Этот ответ также может помочь   -  person Marc Durdin    schedule 12.05.2021


Ответы (5)


С GNU sed и bash:

  sed -E s/$'\u2601\uFE0F?'//g emoji.txt
person M. Nejat Aydin    schedule 10.08.2020
comment
В оболочке Z (zsh) замените ? на \?. - person Culip; 13.08.2020
comment
@Culip Ты прав. Также лучше поместить ? внутри $' ' в bash. В противном случае он будет интерпретирован как шаблон соответствия имени файла. Я исправил это. - person M. Nejat Aydin; 13.08.2020

Пусть awk напечатает все поля, кроме последнего:

$ awk '/^Standard/ || /^Variant form/ { $(NF)="" }1' emoji.txt
Standard
Variant form

ПРИМЕЧАНИЕ. Это конкретное решение оставит разделитель полей (пустым) в конце строки вывода; если вы хотите удалить конечный пробел, вы можете подключиться к sed, tr и т. д. ... или awk перебрать поля с 1 по (NF-1) и вывести через printf

person markp-fuso    schedule 10.08.2020
comment
Извините, markp-fuso, emoji.txt был просто примером. Опять же, мой вопрос заключается в том, как удалить смайлики с альтернативной escape-последовательностью или без нее. - person Culip; 11.08.2020

Вы можете использовать awk, например:

$ cat emo.ascii 
Standard \x2601
Variant form \x2601\xFE0F
$ ascii2uni -a B emo.ascii                                  
Standard ☁
Variant form ☁️
3 tokens converted # note: this is stderr
$ ascii2uni -a B emo.ascii | awk -F' ' '{NF--}1' | cat -A 
3 tokens converted # note: this is stderr
Standard$
Variant form$

NF-- уменьшит количество полей в awk, что фактически удалит последнее поле. 1 оценивается как true, что заставляет awk печатать измененную строку.

(Здесь используется cat -A только для того, чтобы показать, что не осталось невидимых символов)

person hek2mgl    schedule 10.08.2020

Используйте команду nkf. nkf -s попробуйте преобразовать кодировку символов в Shift-jis, которая не поддерживает смайлики. Поэтому эмодзи и escape-последовательность исчезнут. Наконец, верните ввод в UTF-8 с помощью nkf -w.

$ cat emoji.txt | nkf -s | nkf -w
Standard
Variant form

$ cat emoji.txt | nkf -s | nkf -w | od -tx1c
0000000  53  74  61  6e  64  61  72  64  20  0a  56  61  72  69  61  6e
          S   t   a   n   d   a   r   d      \n   V   a   r   i   a   n
0000020  74  20  66  6f  72  6d  20  0a
          t       f   o   r   m      \n
0000030

Я подумал, что ruby может сработать. Потому что \p{Emoji} соответствует смайликам. Но остаются escape-последовательности.

$ ruby -nle 'puts $_.gsub!(/\p{Emoji}/,"")' emoji.txt
Standard
Variant form ️

$ ruby -nle 'puts $_.gsub!(/\p{Emoji}/,"")' emoji.txt | od -tx1c
0000000  53  74  61  6e  64  61  72  64  20  0a  56  61  72  69  61  6e
          S   t   a   n   d   a   r   d      \n   V   a   r   i   a   n
0000020  74  20  66  6f  72  6d  20  ef  b8  8f  0a
          t       f   o   r   m           217  \n
0000033

person Gre-san    schedule 10.08.2020
comment
Нет, вам не следует преобразовывать Unicode в Shift JIS или любой другой набор символов для определенного языка. Исходный текст может включать различные символы, например арабские. По совпадению, я тоже говорю по-японски, и я бы использовал iconv, а не nkf. - person Culip; 11.08.2020
comment
Я заметил, что \p{Emoji_Component} соответствует escape-последовательности для эмодзи (ссылка ). Большинство движков регулярных выражений не поддерживают его, но Rust поддерживает. Установите sd и sd '([^#*0-9\P{Emoji_Component}]|[^#*0-9\P{Emoji}])' '' < emoji.txt получите то, что вам нужно. - person Gre-san; 11.08.2020

Преобразуйте текстовый файл Unicode в ASCII и удалите те символы Unicode, которые представлены символами ASCII, и снова преобразуйте его в UTF-8:

$ uni2ascii -q ./emoji.txt | sed "s/ 0x2601\(0xFE0F\)\?//g" | ascii2uni -q
Standard 
Variant form 
$
person Culip    schedule 10.08.2020