Windowsのバッチファイルで、Perlを使って特定の文字列を含む行を抽出する処理を行っているのですが、うまくいかないケースがあります。
例えば、以下の線内のようなテキストがあって、
----------------------
〔a
〔A
゜a
゜A
----------------------
大文字/小文字を問わず、「〔a」を含む行を抽出し、
以下の線内のような結果を得たいとします。
----------------------
〔a
〔A
----------------------
検索対象ファイルの文字コードが「Shift-JIS」で、
「print if ( /〔a/i );」という構文で行を抽出すると、
以下の結果になってしまいます。
----------------------
〔a
〔A
゜a
゜A
----------------------
「print if ( /〔a/ );」なら以下の結果になってしまいます。
----------------------
〔a
----------------------
検索対象ファイルの文字コードを「UTF-8」にし、
「print if ( /〔a/ );」という構文で、
「〔a」を含む行を抽出しようとすると、何も行が抽出されません。
他のコマンドでの大文字/小文字問わない「〔a」を含む行の抽出は、
findstrでは得たい結果が得られ、
grep、AWKでは、Perl同様、「゜a」を含む行が抽出されてしまいます。
しかし、私が行いたい処理は、数百~数千程度の単語が書かれた単語のリストがあり、そのリストをスクリプト形式に置換して行を検索するので、スクリプトファイルに対応していないfindstrコマンドでは不便なのです。
上記の問題の原因が分かる方がおられましたら、お教え頂けないでしょうか。
No.1
- 回答日時:
〔a ==> \x81ka
〔A ==> \x81kA
゜a ==> \x81Ka
゜A ==> \x81KA
print if (/\x81ka/i);
〔 の文字コードが 81 6B (6B は小文字の k) で、゜の文字コードが 81 4B (4B は大文字の K) のため、i 修飾子を付けるとすべてマッチしてしまうことになります。Shift_JIS の2バイト目にはアルファベットに該当する文字がたくさんあるため、i 修飾子を使うと別の文字にマッチしてしまう危険があります。
パターン修飾子は正規表現の内部にも書くことができ、次のようにすれば 〔a と 〔A のみを抽出できるようになります。
print if (/〔(?i)a/);
ご回答、ありがとうございます。大変よく分かりました。
実際に作業で使うリスト内の単語は様々で、「あaいi」の様に、2バイト文字と半角文字が複数回交互に来る場合もあるので、単語リストをスクリプトに置換する時、「print if (/あ(?i)aいi/);」にすると、2バイト文字の「い」が「(?i)」より後に来てしまいますし、「print if (/あaい(?i)i/);」とすれば「a」が半角のみにマッチしてしまうと思うので、なかなか難しいです。
実際作業に使用するリストの単語は、2文字以上の場合が多いので、今回の件が原因での不具合は起こり辛いのですが、不完全な仕組みで長期間処理を続けて、いつか不具合が起きると嫌なので、出来れば完璧に間違いのない行の抽出をしたいのです。
ただ、ご回答の内容で大変よく分かりましたので、なんとか解決策を見付けられそうです。ご回答、ありがとうございました。
No.2
- 回答日時:
入力 (と出力) の際に, 内部コードとの間で文字コードを変換する.
必要であればスクリプトで使っている文字コードも指定する.
この回答への補足
色々調べてみたのですが、単純にスクリプトに1、2行足せばいいというものではなく、もう少し複雑になる様で、そうなると色々と勉強しなければつまずく箇所が多いので、今回はこちらの方法は見送ろうと思います。
一応、WEBにあったサンプルのコードを、そのままコピペして実行してみたのですが、環境が合っていないのか、エラーが出てうまく行かないので、実現まで時間が掛かりそうなのです。
Perlに関する本は手元にあるので、時間がある時に勉強して、マスターしたら今回の問題を解決しようと思います。
ご回答、ありがとうございました。
ご回答、ありがとうございます。
Perlのスクリプト内に、ファイルからのデータを入出力の際、文字コードを変換する処理を書くということでしょうか。
自分はあまりPerlに詳しくないので、今から調べてやってみようと思います。
出来たらまた追記したいと思います。ご回答ありがとうございました。
No.3
- 回答日時:
書くのが面倒と言えば面倒なのですが、(?i) には別の書き方があります。
print if (/あ(?i:a)い(?i:i)/);
?i の直後にコロンを置いて、続けてパターンを書けば外側に影響することはありません。ただ、Shift_JIS の2バイト目には、バックスラッシュや正規表現のメタ文字も含まれるので注意が必要です。
再度、ご回答ありがとうございます。
正規表現で置換コマンドの一文を追加するだけなので、面倒という訳ではないのですが、思い通りの動作をしてくれるかが心配です。
今回お教え頂いた方法を使う場合、Perlの正規表現での置換なら、「s/([a-zA-Z]+)/(?i:\1)/gi;」の様な感じでリストを置換すればいいと思うのですが、「Shift_JIS の2バイト目には、バックスラッシュや正規表現のメタ文字も含まれる」というのが気になります。なんとなくおっしゃっている意味は分かりますが、正直まだ完璧には理解出来ていません。
もう一つ私が考えている方法としましては、あまりスマートな方法ではないかも知れませんが、全てのアルファベットを、「[Aa]」のように置換する方法です。
Perlでの置換なら、「 s/[Aa]/[Aa]/gi; s/[Bb]/[Bb]/gi; … s/[Zz]/[Zz]/gi; 」の様な感じで置換するという事です。「あaいi」は「あ[Aa]い[Ii]」と置換されます。
こちらの方が安全かと思うのですが、同じことなのでしょうか。
つまり、
「print if (/あ(?i:a)い(?i:i)/);」と、
「print if (/あ[Aa]い[Ii]/);」なら
どちらがいいのかという事です。同じでしょうか。
とにかく、もう少し調べてみようと思います。ご回答ありがとうございました。
No.4
- 回答日時:
現状どんなスクリプトなのかまったくわからんので想像するしかないんだけど, たいてい
ファイルから入力する (このときに内部コードに変換する)→なんかする→出力する (このときに内部コードから変換する)
でいけると思うんだ.
あ, もちろん Perl のバージョンに依存する部分はあるけどね.
再度、ご回答ありがとうございます。
私はPerlの文法が分からないので、スクリプトは、単純に単語のリストをスクリプト形式に書き換えただけのものです。
「りんご」と書かれた行なら、「print if ( /りんご/ );」と置換しているだけです。
それをバッチファイルから「perl -n "script.pl" "in.txt" > "out.txt"」の様な感じで実行しています。
スクリプトの件ですが、色々試してみましたが、エラーは出るものの、以下のようにするとうまくいきました。
--------------------------------
■ バッチファイルの内容
perl "script.pl" "in.txt" > "out.txt"
■ スクリプトファイル「script.pl」の内容
use strict;
use warnings;
use utf8;
use open IO => ":utf8";
while (<>) {
print if ( /〔a/i );
}
■ 入力ファイル「in.txt」の内容
〔a
〔A
゜a
゜A
■ 出力ファイル「out.txt」の内容
〔a
〔A
■ 文字コード
in.txt(UTF-8)
out.txt(UTF-8)
script.pl(UTF-8)
■ エラーメッセージ
Wide character in print at script.pl line 7, <> line 1.
Wide character in print at script.pl line 7, <> line 2.
--------------------------------
これで目的は達成出来ましたので、後は地道に調べてエラーも出来れば消そうと思います。
あと何時間かしたら質問を締め切らせて頂こうと思いますので、それまでにもし何かアドバイス等ございましたら頂けると有り難いです。
ご回答ありがとうございました。
No.5ベストアンサー
- 回答日時:
すみません, ちょっと確認ですが
print if ( /〔a/i );
を
print Encode::encode('utf-8', $_) if ( /〔a/i );
にしたら (これでエラーになるなら use Encode; を最初の方に追加して上の Encode::encode をただの encode にする) どうなるでしょうか?
余談ですが, この位置に if をつけるときにはかっこはなくてもよかったりします.
「print if ( /〔a/i );」を「print Encode::encode('utf-8', $_) if ( /〔a/i );」に変えただけなら、「Undefined subroutine &Encode::encode called at script.pl line 7, <> line 1.」というエラーが出ました。
上記に加え、「use Encode;」も記述するとエラーは出なくなりました。大変助かりました。ありがとうございました。
あと、かっこの件ですが、この場合は要らないのですね。勉強になりました。
私はまだPerlの構文を理解していないので、WEBにあったサンプルコードを自分なりに書き換えて使っていまして、使い方を間違っている部分もありますね。お恥ずかしいです。
おかげさまで完璧に行の抽出が出来るようになりました。大変助かりました。ご回答、本当にありがとうございました。
No.6
- 回答日時:
> Perlでの置換なら、「 s/[Aa]/[Aa]/gi; s/[Bb]/[Bb]/gi; … s/[Zz]/[Zz]/gi; 」の様な感じで置換するという事です。
「あaいi」は「あ[Aa]い[Ii]」と置換されます。$foo = 'アaイi';
$foo =~ s/[aA]/[aA]/gi;
$foo =~ s/[iI]/[iI]/gi;
print "$foo\n"; # ゼaA][aA]イ[iI]
確かに「あaいi」ではうまくいきますが、カタカナにした「アaイi」では文字化けしてしまいます。「ア」の2バイト目が大文字の "A" になっているからです。(ちなみに「イ」の2バイト目は "C" ですので、s/[cC]/[cC]/gi; を適用すると文字化けすることになります。)
Shift_JIS は厄介な文字コードですので、utf8 または euc-jp で Perl プログラムを書くことができるのでしたら、そちらの方がトラブルに見舞われることが少なく楽をすることができます。(「/〔a/i」や「/あaいi/i」もそのままで実行できると思います。)
再度、ご回答ありがとうございます。
なるほど、つまり、「[aA]」の様にしても意味がないという事ですね。Shift_JIS使うと大変ややこしくなるのですね。大変参考になりました。今後はなるべくUTF-8等を使って行こうと思います。
「〔」と「゜」の問題は、Perlスクリプト内で文字コードをUTF-8にする事で解決出来ました。ありがとうございました。
今回は色々と勉強になりました。長い間付き合って頂き、本当にありがとうございました。大変助かりました。
ご回答、本当にありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- その他(データベース) Accessのクエリで1フィールドの抽出条件設定をNullでなく全角半角含む空白のみの文字列でない文 1 2023/04/24 15:20
- Excel(エクセル) PHPプログラムをエクセルに張り付けると検索ボックスがでてくる! 3 2022/05/08 07:10
- Excel(エクセル) Indirect関数について、Formulatextで抽出した数式を参照したい。 1 2022/12/15 11:16
- Excel(エクセル) エクセルで#以降の文字を取得したい 1 2022/03/28 13:14
- Excel(エクセル) エクセルで2つの表を比較して、文字列が同じだが、その行のある値が違うものを抽出したい 1 2022/10/06 21:48
- Visual Basic(VBA) Excel VBAでAA(BBB) → BBB.AA に置換したい 2 2022/10/30 13:59
- Visual Basic(VBA) EXCEL VBA 単語置き換え について質問です ブック名 ぶぶぶ シート名 ししし セル V3〜 3 2023/03/08 01:41
- Visual Basic(VBA) VBA初心者です 検索した数字の行に色をつける 5 2023/02/13 14:22
- PHP SQLとPHPの連結方法がわからないのでアドバイスお願い致します 1 2022/07/12 12:16
- その他(Microsoft Office) Outlookメール 連絡先の検索について 〈 ご説明 〉 Windows PC の Outlook 1 2022/09/23 14:43
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
各項目がダブルクォーテーショ...
-
csvデータ ダブルクォーテ...
-
正規表現で、特定の文字列を含...
-
VBA 置換文字がみつからない時
-
正規表現 特定の文字列を含む行...
-
csvデータのダブルクォーテーシ...
-
Replace関数 大文字小文字を区...
-
word VBA 改ページの繰り返しに...
-
C言語でテキストファイルの内容...
-
置換文字列の中に"?"があると置...
-
\\(円)記号を置換したい
-
xmlファイル内の文字列置換
-
テキストファイル中の文字列の置換
-
Perl での XML 置換について
-
複数のパワーポイントファイル...
-
Eclipse 改行後のタブ
-
パワーポイントの一括置換:複...
-
秀丸で数字だけの行を削除したい
-
秀丸での一括変換について
-
テキストボックスの文字列を置...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
csvデータのダブルクォーテーシ...
-
VBA 置換文字がみつからない時
-
csvデータ ダブルクォーテ...
-
各項目がダブルクォーテーショ...
-
正規表現で、特定の文字列を含...
-
スペースで区切られた氏名から...
-
xmlファイル内の文字列置換
-
正規表現 特定の文字列を含む行...
-
○文字目に文字挿入
-
PowerShellでテキストの空白行...
-
EXCEL警告「置換対象のデータが...
-
ハングルを日本語に置換
-
C#で空白行を削除する方法
-
python 大文字小文字を区別しな...
-
EXCELマクロを用いてグラフの系...
-
EXCEL VBA でCTRL+Fのダイア...
-
テキストファイル中の文字列の置換
-
word オートシェイプ内も一括変換
-
Excel・ユーザーフォームの情報...
-
テキストボックスの文字列を置...
おすすめ情報