WEB相談室

Webページ作成に関しての何でも掲示板です。

タイトル:全角文字と半角文字の正規表現

0:[投稿] 中根 [URL] [2002/08/27 00:14 ][環境:WIN+IE WIN系+Perl]

こんにちは、中根です。

文字コードがEUCで、あるHTML文字列$strが与えられているとします。
この$strに対して、全角文字と半角文字の間に半角スペースを一つずつ
はさむ、という処理をPerlで行いたいのですが、どう書けばよいでしょうか?

「<p>文字コードがEUCで、あるHTML文字列$strが与えられているとします。</p>」を、
「<p>文字コードが EUC で、ある HTML 文字列 $str が与えられているとします。</p>」
としたいのです。タグの<や>と全角文字の間にスペースを入れる必要はありません。

今まではDreamweaverで、検索対象をサイト全体として、テキストの
「([、-熙])([!-;=?-~])」を「$1 $2」に置き換えていましたが、
コンテンツによっては置き換えてはまずいものがあり、
Perlで置き換えの可否を判断する必要が出てきました。

よろしくお願いします。


1:[回答] TOM neko [2002/08/28 02:29 ]

タグの中か外か判別する必要がないなら、
$str =~ s/([\x21-\x3B\x3D\x3F-\x7E])([\x80-\xFF])/$1 $2/g;
$str =~ s/([\x80-\xFF])([\x21-\x3B\x3D\x3F-\x7E])/$1 $2/g;
Dreamweaverの正規表現と余り変わらないですね。


2:[回答] tetti [2002/08/28 18:17 ]

はじめまして、ここにははじめて書き込みます。
以後よろしくお願いします。

ちょっと興味があったので書いてみました。
EUCは普段使わないので、ちょっと自信ないです。


my $str = '「<p>文字コードがEUCで、あるHTML文字列$strが与えられているとします。</p>」';

my $hankaku = '[!-~]'; # コントロール文字とスペースを除いた1バイト文字
my $zenkaku = '(?:[\x8E\xA1-\xFE][\xA1-\xFE]|\x8F[\xA1-\xFE][\xA1-\xFE])';

$str =~ s{(?:^|(?<=>))([^<]*)}
        {
          my $text = $1;
          $text =~ s{($hankaku+)($zenkaku+)}{$1 $2}ogs;
          $text =~ s{($zenkaku+)($hankaku+)}{$1 $2}ogs;
          $text;
        }egs;

print $str;


タグの表現は簡易なもので、< が始まれば、必ず > で閉じてあると仮定してあります。
また、<> の中に <> は、出現しないとも仮定してあります。
即ち、<!-- <P> --> などに出会うと、まずいことになります。
厳密にやりたければ、HTML関係のモジュールを使った方がよいでしょうね。


3:[回答] Mr.X [2002/08/28 23:17 ]

> タグの<や>と全角文字の間にスペースを入れる必要はありません。
回答じゃないんですが、
「明日は<span>Ever17</span>の発売日」のように
ASCII と日本語の境界にタグがある場合は例示されたコードだと素通しですが、
考慮しなくてもいいのでしょうか?


4:[回答] 中根 [URL] [2002/08/29 11:56 ]

こんにちは。
お返事ありがとうございます。

「tetti」さんのコードが、一番目的の動作に近いような気がします。
「<p title="テスト">文字コードがEUCで、あるHTML文字列$strが与えられているとします。</p>」
のようなコードでも、きちんと処理できました。

ただ、正規表現中の、「?<=>」の意味がよく分かりません。
http://www.din.or.jp/~ohzaki/regex.htm#ReplaceOutside
に同じようなコードが載っていますが、「後読みと先読みにして外に出すことができる」とは
どういう事でしょうか?

「Mr.X」さんの指摘されたようなパターンは、いったん無視して処理した後、
後から戻って処理する事でなんとかなりそうです。

問題はJavaScriptがある事です。
http://www.din.or.jp/~ohzaki/perl.htm#AutoLink
この辺りが使えそうなので、もう少し粘ってみます。


5:[回答] 中根 [URL] [2002/08/31 12:19 ]

こんにちは、中根です。

コメント、XMP,PLAINTEXT,SCRIPT,CODE,KBD,SAMPタグ内部以外の場所で、
全角文字と半角文字境界に半角スペースを入れるスクリプトを書いてみました。
ただし、「abcdef」や"あいうえお"のような場合には、スペースを挿入しません。

いろいろなHTMLで試してみたところ、正常に動いているようですが、
穴がありそうで怖いです。
これで合っているでしょうか?

# Perlメモ http://www.din.or.jp/~ohzaki/perl.htm を参考にしました。
# ありがとうございます。
#コメント以外のタグ
$tag_regex_ = q{[^"'<>]*(?:"[^"]*"[^"'<>]*|'[^']*'[^"'<>]*)*(?:>|(?=<)|$(?!\n))};
#コメントタグ
$comment_tag_regex = q{<!(?:--[^-]*-(?:[^-]+-)*?-(?:[^>-]*(?:-[^>-]+)*?)??)*(?:>|$(?!\n)|--.*$)};
#タグ
$tag_regex = qq{$comment_tag_regex|<$tag_regex_};
#タグ外部のテキスト
$text_regex = q{[^<]*};
#「"'()[]」は除外した、半角文字
# ASCIIコードの順序は「!"#$%&'()*+'-./数字:;<=>?@大文字[\]^_`小文字{|}~」
$hankaku = q{[\!\#-\&\*-Z\\^-~]};
#EUC-JPでの二バイト文字。括弧類以外。半角カタカナは無視
# 1バイト目は0xA1から0xFE,2バイト目も0xA1から0xFE
# 括弧類があるのは、以下の部分。
#         1  2  3  4  5  6  7  8  9  0  A  B  C  D  E  F
# a1 cX | \ 〜 ‖ | … ‥ ‘ ’ “ ” ( ) 〔 〕 [ ]
# a1 dX | { } 〈 〉 《 》 「 」 『 』 【 】 + − ± ×
$zenkaku = '(?:[\xA1][\xA1-\xC6\xDD-\xFE] |' #括弧類は除外
         .'[\xA2-\xFE][\xA1-\xFE])';

$result = ''; #結果をクリア
while ($str =~ /($text_regex)($tag_regex)?/gso) { #テキスト、タグの順で分離
 last if $1 eq '' and $2 eq '';
 $text_tmp = $1; #テキスト
 $tag_tmp = $2; #タグ
 
 #テキスト部分のみ、スペースを挿入する
 $text_tmp =~ s/($hankaku+)($zenkaku+)/$1 $2/gso;
 $text_tmp =~ s/($zenkaku+)($hankaku+)/$1 $2/gso;
 
 $result .= $text_tmp . $tag_tmp; #結果に付け加える
 
 #XMP,PLAINTEXT,SCRIPT,CODE,KBD,SAMPタグ内部は無視
 if ($tag_tmp =~ /^<(XMP|PLAINTEXT|SCRIPT|CODE|KBD|SAMP)(?![0-9A-Za-z])/i) {
   $str =~ /(.*?(?:<\/$1(?![0-9A-Za-z])$tag_regex_|$))/gsi;
   $result .= $1;
 }
}


6:[回答] tetti [2002/08/31 18:13 ]

こんにちは。

>ただ、正規表現中の、「?<=>」の意味がよく分かりません。

(?<=パターン) で、意味を持ちます。
例えば、 /(?<=saki)yomi/ は、'saki' に続いて 'yomi' が来る文字列にマッチするけど、'saki' そのものはマッチ対象に含ませないといったことが出来ます。

つまり (?<=>) の意味は、'>' を目印に次のパターンを探してるけど、'>' そのものは含めないといった意味です。

$str = '<p>p</p>';
$str =~ s/(?<=>)p//;
print $str; # 結果 <p></p>


>いろいろなHTMLで試してみたところ、正常に動いているようですが、
>穴がありそうで怖いです。
>これで合っているでしょうか?

何通りかテストしてみましたが、特に問題ないように思います。
ただ、Mr.Xさんの指摘の問題はなかなか難しそうですね。


7:[完了] 中根 [2002/09/08 11:53 ]

こんにちは、中根です。

Mr.Xさん指摘の件ですが、
($text_regex)($tag_regex)($text_regex)を切り出して、
$1の末尾と$2の頭を処理する。
次に、HTML全体からタグ一つ文だけ切り離して、
残った部分で同じ処理をする(一つずれた形になる)。

―という形で何とかなりそうですが、自分のサイトには
このようなパターンはほとんど無かったのでコードは書いていません。

とりあえず、完了とします。ありがとうございました。

回答(必須): 状態:

お名前(必須):

e-mail:

URL:




[戻る]

ChaichanPAPA's World