web-dev-qa-db-ja.com

sedで特別な「M-BM-」文字を削除する方法

LibreOfficeを使用してDOCXドキュメントのコンテンツをテキストファイルにコピーして作成したファイルがあります。 sedでファイルを変更して、追加のスペースやその他のものを削除しましたが、通常のコマンドの影響を受けないスペースに気付きました。

sed -r 's:some-text :some-text:g' -i file

cat -A fileを使用した後、次のようになっていることがわかりました。

<p>M-BM- Lorem ipsum</p>

削除する方法は?

6
Rafal

多くのことを試した後、私は最終的に解決策を見つけました。その奇妙な文字をsedに置き換えるには、その近くにその奇妙なスペースを含む正確なテキストをコピーして貼り付けてから、sedコマンドに直接貼り付ける必要があります。

sed -r 's:paste-here:<p>:g' -i file

Sedコマンドでは次のようになります。

sed -r 's:<p> :<p>:g' -i file

とにかく動作します。

1
Rafal

M-BM-文字は、バイトシーケンス0xc2 0xa0のASCII表現です。これは、Unicode文字のUTF8エンコードA0-改行しないスペース文字です。この文字は、キーシーケンスを使用してLibreOfficeとMicrosoft Wordドキュメントの両方に挿入できます Ctrl+Shift+SPACE

たとえば、LibreOfficeで新しい.odtドキュメントを作成し、ABCと入力した場合Ctrl+Shift+SPACEDEF、次にSave As... Text(ドキュメントにその形式では保存できない機能が含まれている可能性があるという警告を無視)、結果の.txtファイルをcatで表示します。

$ cat nbsp.txt 
ABC DEF

その後、-vスイッチを使用して、非印刷文字を表示します

$ cat -v nbsp.txt 
M-oM-;M-?ABCM-BM- DEF

また、fileコマンドによって報告されるファイルタイプと一致するUTF8 バイトオーダーマーク(BOM) である初期シーケンスM-oM-;M-?または16進数0xef 0xbb 0xbfを取得することに注意してください。

$ file nbsp.txt 
nbsp.txt: UTF-8 Unicode (with BOM) text

odを使用して、16進値をバイト順で出力します

$ od -tx1 nbsp.txt
0000000 ef bb bf 41 42 43 c2 a0 44 45 46 0a
0000014

エスケープシーケンスとして16進コードを指定することにより、sedtrなどの標準ツールを使用してこれらの文字を操作することができます。非分割スペースをプレーンASCIIスペースに置き換える

$ sed 's/\xc2\xa0/ /g' nbsp.txt
ABC DEF

odで再度確認すると、通常のASCIIスペース0x20(10進数32)による置換が確認されます。

$ sed 's/\xc2\xa0/ /g' nbsp.txt | od -tx1
0000000 ef bb bf 41 42 43 20 44 45 46 0a
0000013

Gnome-terminal(および他のUTF8対応ターミナルエミュレータ)では、キーシーケンスを使用してunicodecode point valueを直接入力することもできます Ctrl+Shift+u その後に16進数値が続き、 Enter キー-シーケンスは最初はu̲.̲.̲.̲として表示されますが、ヒットするとキャラクターが構成されます Enter 例えば私たちができる同じノンブレークスペースの交換のために

$ sed 's/Ctrl+Shift+ua0

として表示されます

$ sed 's/̲/̲u̲a̲0̲

そして、次のように完了します

$ sed 's/ / /g' nbsp.txt
ABC DEF

cat -vを使用して、M-BM-シーケンスが通常のスペースになったことを確認できます。

$ sed 's/ / /g' nbsp.txt | cat -v
M-oM-;M-?ABC DEF

iconvuconvなどのより一般的なエンコーディングコンバーターもご覧ください。

11
steeldriver

「cat -v file」は、ファイル内の非印刷文字を表示します。出力を一時ファイルにリダイレクトし、Vimを使用してM-BM-文字を何も置き換えないでください。

%s/M-BM- // g

最も簡単なソリューション。

1
Prasad

Sedコマンドを使用して、ファイルから^ Mを直接削除できます。例:

sed -i'.bak' s/\r//g *.*

変更に満足したら、.bakファイルを削除します。

rm -v *.bak
1
kenorb

この悪魔M-BM-文字を削除するための小さなスクリプト! ;)万が一に備えて、あらゆる人を助けます。

#!/bin/bash
#############################################################################
# SCRIPT:   M-BM-Remover.sh
# DESCRIPTION:
#           This script will be able to detect hidden caracter "M-BM-",
#               And/Or remove this !
# REVISIONS:
#           2014/06/11  YG
#____________________________________________________________________________
#
# PARAMETERS:
#  > $1  :TARGET,      (e.g. '"*.sh"' )
#  > $2  :ACTION,      (e.g. 'remove' )
#  > $2  :BACKUP,      (e.g. '' )
#
#############################################################################

TARGET=$1
ACTION=$2
BACKUP=$3

if [ "$TARGET" = "" ]
then
    echo 'Need to choose target file'
    echo 'M-BM-Remover [TARGET] [show/remove] [backup]'
    echo 'Example : M-BM-Remover "*.sh" remove backup'
    exit
fi

echo "ACTION = $ACTION";
echo "TARGET = $TARGET";
echo

if [ "$ACTION" = "show" ]
then
    for file in $TARGET
    do
        if [ "$file" != "M-BM-Remover.sh" ]
        then
            echo "Traitement de $file ..."
            cat -v $file | grep M-BM-
            NB=`cat -v $file | grep M-BM- | wc -l`
            echo "Occurence(s) : $NB"
        fi
    done 
fi

if [ "$ACTION" = "remove" ] || [ "$ACTION" = "" ]
then
    for file in $TARGET
    do
        if [ "$file" != "M-BM-Remover.sh" ]
        then
            echo "Traitement de $file ..."
            NB=`cat -v $file | grep M-BM- | wc -l`
            if [ "$BACKUP" = "backup" ]
            then
                cat $file > $file.bak
            fi
            cat -v $file.bak | sed s/M-BM-//g > $file
            echo "Occurence(s) removed : $NB"
        fi
        echo
    done 
fi
0
YoannG