I have some long strings of Chinese characters, but for the sake of the question, let's suppose they are:




The first string lists all of the "easy" Chinese characters. The second string lists all "easy" and "intermediate" Chinese characters, but I only want the "intermediate" Chinese characters: I want to delete the "easy" characters from the second string.

E.g. after editing, the second string will not contain 啊 nor 爱 (and perhaps more deletions) since they both occur in the first string.

Question: How do I remove Chinese characters from string B whenever they occur in string A, while preserving the order?

I feel like this should be solvable with awk or sed or something; I don't mind. It looks like I could convert these strings to two text files, and use any one of the commands in How to remove the lines which appear on file B from another file A? However, I'd rather do it without creating auxiliary files.

It's also important to retain the order of the characters in the strings.

3 Answers 3


In shells that allow the syntax ${parameter/pattern/string} (ksh,bash,zsh) you can do:

$ easy='啊爱好情人心安静排全装按照八把握爸吧白菜酒色夭百班长板'
$ intermediate='阿姨啊挨打矮小爱国护安检慰置岸边上按摩时案子暗示巴士拔'

$ echo "${intermediate//[$easy]/}" 

That is based on a regex-like selection of characters […].
All individual characters in intermediate that also exist in easy will be erased.

An equivalent that is independent of the shell may be:

$ echo "$intermediate" | sed 's/['"$easy"']//g'


using Raku (née Perl6)

Raku was designed from the ground-up to handle Unicode gracefully. First example of each pair below generally from the Raku docs; second example of each pair adapted to solve with your particular Chinese strings:

$ echo "a123b123c" | raku -pe 'tr:d/123//;'
$ echo "阿姨啊挨打矮小爱国护安检慰置岸边上按摩时案子暗示巴士拔" | raku -pe 'tr:d/啊爱好情人心安静排全装按照八把握爸吧白菜酒色夭百班长板//;'


$ echo "a123b123c" | raku -pe '.=trans("123" => "");'
$ echo "阿姨啊挨打矮小爱国护安检慰置岸边上按摩时案子暗示巴士拔" | raku -pe '.=trans("啊爱好情人心安静排全装按照八把握爸吧白菜酒色夭百班长板" => "");'

The -pe command-line flags instruct Raku to take input linewise and autoprint the return value(s). There are minor differences between the tr/// operator and the trans() routine. Docs below, HTH.



I figured it out! It may not be the best solution, but it works:

echo 阿姨啊挨打矮小爱国护安检慰置岸边上按摩时案子暗示巴士拔 | sed -e "s/.\{1\}/&\n/g" | awk -v pat="啊爱好情人心安静排全装按照八把握爸吧白菜酒色夭百班长板" 'pat ~ $0' | tr -d '\n'


  • echo 阿姨啊挨打矮小爱国护安检慰置岸边上按摩时案子暗示巴士拔 is a way to pipe the second string as input
  • sed -e "s/.\{1\}/&\n/g" adds a newline after each character
  • awk -v pat="啊爱好情人心安静排全装按照八把握爸吧白菜酒色夭百班长板" 'pat !~ $0' prints only the characters that do not occur in pat (the first string)
  • tr -d '\n' gets rid of all the newlines

It gives the output


and removes the characters 啊, 爱, 安, and 按.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .