
Perlで、UTF-8のテキストファイル内の文字列置換をワンライナーで行いたいのですが、可能でしょうか。
現状は、以下のような書式を実行しています。
perl -pi.bak -e "s/置換前/置換後/gi;" "入力.txt"
しかし、上記ですと、入力ファイルの文字コードがUTF-8では処理されません。
UTF-8のファイルを処理するにはどのようにしたら良いでしょうか。ワンライナーでは無理でしょうか。
環境は、Windows10、ActivePerl(perl 5, version 28, subversion 1 v5.28.1)です。
ご存じの方がおられましたら、お教え頂けると有難いです。

No.6ベストアンサー
- 回答日時:
>現状、「mfind」というプログラムを使うと、UTF-8のファイルでも正常に置換出来ます。
ただ、少し動作が重いです。No4です。
こちらで、perlの置換スクリプトを作成して、mfindとで実行時間を比較してみました。(時間計測はしていません)
mfindの場合、検索結果を画面に表示しているので、その為に遅くなっているように見えます。
画面出力をnullにリダイレクトすると圧倒的に早くなります。
perlの置換スクリプトよりはmfindのほうがかなり早いです。
perlのワンライナーとmfindが同等の感じでした。
その為、置換スクリプトが正規表現を使えたとしても、実行速度が遅いので今回の用途には使えないと考えます。
mfindにリダイレクト処理をいれて試されてはいかがでしょうか。
mfind /W /Q /E8N "/aaa/bbb/g" 入力.txt > null
のようにします。
mfindで十分対応可能かと考えます。
再度、ご回答ありがとうございます。
> aaaとかbbb個所に日本語が入ることはありますか?
「s/aaa/bbb/gi;」に日本語が入ることはあります。UTF-8の文字(「♡」等)が入る事はほぼ無いかと思います。
> 画面出力をnullにリダイレクトすると圧倒的に早くなります。
試してみましたが、おっしゃる通り、リダイレクトと「/Q」オプションを付けると、かなり高速化出来ました。ありがとうございます。
あと、for文によるループ処理ではなく、mfindの「/S」オプションでサブディレクトリを処理するようにしたら、更に高速化出来ました。
以前の私のmfindの記述ですと、処理に10倍以上の時間が掛かっていましたが、お教え頂いた改善で十分実用出来る速度になりました。この書式を使っていこうと思います。
おかげさまで解決しました。大変助かりました。本当にありがとうございました。他の方々も本当にありがとうございました。

No.5
- 回答日時:
念のため確認ですが
set 置換処理=s/aaa/bbb/gi; s/ccc/ddd/gi;
のところですが、
aaaとかbbb個所に日本語が入ることはありますか?
例 s/東京/大阪/gi;
もし、に本語が入らないなら、
perl -CS -Mutf8 -pi.bak -e "s/aaa/bbb/gi;"
でOKかと。(aaa,bbbは正規表現可)
Malformed UTF-8 character: のエラーが出ているということは、日本語も入るということでしょうか。

No.4
- 回答日時:
windows環境でワンライナーでのutf-8のファイルの文字置換は、無理があるようです。
スクリプトで良ければ、以下のようなスクリプトは提供可能です。
スクリプト名を仮にsed.plとすると
perl sed.pl 置換前 置換後 入力.txt 出力.txt
とすると、置換後の結果を 出力.txtへ出力します。(入力.txtは変更されません)
置換の仕方は s/置換前/置換後/gi と同じ結果になります。(但し正規表現は使用不可)
入力.txtは必ずutf-8で記述されていることが前提です(BOM無)
そのような仕様で良ければ提供可能です。
ご回答、ありがとうございます。
ご提案頂いたスクリプトの件ですが、大変有難いのですが、どうしても正規表現は使いたいので、今回は遠慮させて頂こうと思います。お気持ちに感謝致します。
詳しい経緯を書きたいのですが、お礼には文字数制限がありますので、補足にて書かせて頂こうと思います。ありがとうございました。
No.3
- 回答日時:
まずは、エラーメッセージを理解しましょう。
Malformed UTF-8 character: \x91 (unexpected continuation byte 0x91, with no preceding start byte) at -e line 1.
というのは
\x91 というバイトコードがUTF-8として解釈しようとしたら不正だよ(Malformed UTF-8 character: \x91)
エラーが発生したプログラムは、 -e で指定された1行目だよ(at -e line 1.)
と言っています。
ということは
s/前/後/g
というスクリプトがUTF-8で書いてないから、理解できない、と言っているのです。
調べると、 前 のSHift_JIS は \x91\x4f です。
1バイト目がエラーメッセージの \x91 と一致します。
つまり、 WindowsのコマンドプロンプトからActive Perlのコマンドラインに -e でスクリプトを指定すると、Shift_JISで渡されるのでははないだろうか、という予想ができます。
> 2はもしかしたら大丈夫かもしれませんが、 \x{????} とコードポイントを使う必要があるかもしれません。
と書いたのは、この部分です。
s/\x{524d}/\x{5f8c}/
と、Unicodeのコードポイントで指定すれば動作するのではないでしょうか?
ワンライナーは諦める(日本語を使わないものに限定する)のが楽かと思います。
再度、ご回答ありがとうございます。
解説、非常に分かりやすかったです。本当にありがとうございます。
入力ファイルの文字コードや、ファイル名等が原因ではなかったのですね。勘違いしていました。
「s/\x{524d}/\x{5f8c}/」の件、試してみたのですが、エラーは出なくなったのですが、残念ながら置換は出来ませんでした。実際の記述は以下の通りです。
perl -pi.bak -CS -Mutf8 -pe "s/\x{524d}/\x{5f8c}/" "in.txt"
ちなみに、上記書式でも、「s/aaa/bbb/」という感じですと、対象がUTF-8のファイルでも置換出来ます。
もう少し色々と試してみます。ありがとうございました。
No.2
- 回答日時:
今確認できる環境ではないのですが
考えられるものとして、次のことがあります。
1.入力ファイルがUTF-8だと解釈されていない
2.コマンドラインで書いた"s/置換前/置換後/gi;" が「期待通りの日本語」と解釈されていない。
1については、こちらで変更できそうです
https://perldoc.jp/docs/perl/5.26.1/perlrun.pod
> -C [number/list]
> -Cフラグは Perl Unicode 機能のいくつかを制御します。
2はもしかしたら大丈夫かもしれませんが、 \x{????} とコードポイントを使う必要があるかもしれません。
ご回答、ありがとうございます。
こちらで色々と試してみたのですが、私はPerlの知識がほとんど無いので、残念ながら1、2を解決するにはかなり時間が掛かりそうです。
ですので、実現が難しいようであれば今回は諦めて別のプログラムを利用する方法を考えようかと思います。ありがとうございました。
No.1
- 回答日時:
この辺りを参考に
https://perldoc.jp/docs/perl/5.8.1/utf8.pod
https://perldoc.jp/docs/perl/5.26.1/perlrun.pod
おそらくは、以下で解決できるかと思います
perl -CS -Mutf8 -pe "s/前/後/g"
ご回答、ありがとうございます。
以下を実行しますと、
perl -pi.bak -CS -Mutf8 -pe "s/前/後/g" "in.txt"
以下のエラーが出ます。
Malformed UTF-8 character: \x91 (unexpected continuation byte 0x91, with no preceding start byte) at -e line 1.
Malformed UTF-8 character (fatal) at -e line 1.
入力ファイルの中身は、「前」1文字のみ記述されています。改行はありません。バイナリデータですと、「E5 89 8D」です。UTF-8(BOM無し)です。
お教え頂いたURLを拝見しましたが、Perlの知識がほとんど無い私には難し過ぎて理解するのに時間が掛かりそうです。
こちらでも色んなオプションや書式を試してはいるのですが、なかなかWEBにある書式のコピー&ペーストではうまくいかず、Perlを基礎から学んでいないと難しいようです。
ですので、実現が難しそうであれば別の方法を考えようと思います。ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- Excel(エクセル) エクセルのVBAについて とあるサイトのコードを参考に、CSVの文字化けを直すVBAを作成しているの 7 2022/11/04 14:15
- UNIX・Linux テキストファイルをページ番号付きでコマンドラインから印刷したい 1 2023/02/22 12:47
- Excel(エクセル) Excelにて、フォルダ内のTextファイルをマクロで統合すると文字化けしてしまう時の解消コード 4 2023/01/01 07:32
- Excel(エクセル) 【VBA】指定フォルダに格納中のテキストファイルをエクセルで処理し結果のエクセルを新規フォルダに保存 1 2022/03/25 14:19
- CGI CGIで出力するhtmlの<!DOCTYPE html>等のタグは要りますか? 2 2023/02/05 21:26
- フリーソフト サクラエディタの正規表現(grep機能)の使い方 3 2022/06/22 10:29
- Windows 8 メモ帳による文字コード変換 2 2022/09/01 18:38
- PHP phpのメールフォームの完了画面でメール受信のコードを書いています。 1 2023/05/31 11:39
- Excel(エクセル) 文字化け。メモ帳でUTF-8に変換後、エクセルへ貼り付けたいです。 3 2022/08/14 07:21
- その他(プログラミング・Web制作) awkの文字列比較はPOSIXロケールまたはCロケールにおいてバイナリ値の比較に使えるか gawkな 1 2023/04/22 09:21
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
正規表現で、特定の文字列を含...
-
VBA 置換文字がみつからない時
-
Excel・ユーザーフォームの情報...
-
csvデータ ダブルクォーテ...
-
フォントの色を保持したままセ...
-
Excel VBA 教えてください。 VB...
-
スペースで区切られた氏名から...
-
\\(円)記号を置換したい
-
特定の列のみ置換を行いたい
-
正規表現で置換
-
秀丸マクロで列ごとに一括置換...
-
各項目がダブルクォーテーショ...
-
テキストボックスの文字列を置...
-
Eclipse 改行後のタブ
-
SQL IIF と REPLACE のやりかた
-
c++で積分のプログラムを実行し...
-
秀丸での一括変換について
-
C#で空白行を削除する方法
-
【Excel VBA】文字列の置換作業...
-
csvデータのダブルクォーテーシ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
VBA 置換文字がみつからない時
-
正規表現で、特定の文字列を含...
-
csvデータ ダブルクォーテ...
-
各項目がダブルクォーテーショ...
-
Excel VBA リストに一致したデ...
-
スペースで区切られた氏名から...
-
秀丸エディタで、「-」や「ー」...
-
EXCELマクロを用いてグラフの系...
-
csvデータのダブルクォーテーシ...
-
C#で空白行を削除する方法
-
EXCEL警告「置換対象のデータが...
-
xmlファイル内の文字列置換
-
正規表現 特定の文字列を含む行...
-
テキストボックスの文字列を置...
-
○文字目に文字挿入
-
C言語でテキストファイルの内容...
-
複数のパワーポイントファイル...
-
c# ビルド直前にコードを置換で...
-
Excel・ユーザーフォームの情報...
-
\\(円)記号を置換したい
おすすめ情報
今回の質問の目的は、大量のUTF-8のHTMLファイルの文字列置換でして、世の中に複数ファイル対応の文字列置換ソフトはあるのですが、少し自分が欲しいものと細かい挙動等が違っていまして、出来ればスクリプトやバッチファイルで実現したいと思っています。
次の補足に、作成中のバッチファイルのおおまかな例を書きます。
――――――――――――――
@echo off
rem ■ 設定
set "対象フォルダ=C:\xxx"
set 対象ファイル=*.txt
set 置換処理=s/aaa/bbb/gi; s/ccc/ddd/gi;
set 出力文字コード=w
rem ■ バックアップ
pushd "%対象フォルダ%"
pushd ..\
md "バックアップ"
7za a "バックアップ\%date:/=%%time::=%.7z" "%対象フォルダ%"
rem ■ 置換ループ
for /r "%対象フォルダ%" %%a in (%対象ファイル%) do (
nkf -w --overwrite "%%~a"
onigsed -i.bak -R -e "%置換処理%" "%%~a"
nkf -%出力文字コード% --overwrite "%%~a"
)
――――――――――――――
補足したバッチファイルのように、スクリプトの上部に設定箇所があり、そこだけ書き換えれば動作するようにしたいです。
間違えてShift_JISで保存しているHTMLファイルもあるかも知れないので、一応、置換前に「nkf」にて「UTF-8(BOM無し)」に変換し、置換後に、指定された出力文字コードに変換します。
補足したバッチファイルを実行すると、「onigsed(sed)」の部分で、入力ファイルがUTF-8の為、うまく処理出来ません。ここにPerlのワンライナーを入れたいのです。
現状、「mfind」というプログラムを使うと、UTF-8のファイルでも正常に置換出来ます。ただ、少し動作が重いです。
ですので、Perlの方が高速かと思い、今回の質問をさせて頂いた次第です。
これと同様の事が出来るのであれば、Perlやその他のスクリプト言語でも構いませんので、お教え頂けると有難いです。