正規表現DLLに検索文字列などとして渡されNo.39771
fzok4234 さん 22/05/24 10:45
 
おはようございます。fzok4234 です。


スレッド
  https://www.maruo.co.jp/hidesoft/2/x39752_.html#39752
で論点が分かりづらくなってきたので改めて投稿させていただきます。

秀丸エディタが正規表現 DLL に検索パターンや検索対象文字列として LPSTR 型とし
て渡している、Shift-JIS を拡張した
「秀丸独自コード」についてです。


1.  現在、秀丸エディタが HmJre.dll やその互換正規表現 DLL に渡す検索パターン
や検索対象文字列は UTF-16LE などの
    「真正」の Unicode バイトシーケンスではなく、御社が独自に定義した仕様が
「非公開」の「秀丸独自コード」と
    なっています。このため当方を始めとして第三者が HmJre.dll 互換の正規表現
DLL を作ろうとすると、この
    「仕様非公開」の「秀丸独自コード」を処理しないといけないという問題に突き
当たってしまいます。
   
    特に、鬼車 などの既存の Unicode 対応正規表現エンジンのラッパー DLL を作
る際には、この「秀丸独自コード」を
    一般的に通用する UTF-8 などの「真正」の Unicode バイトシーケンスに変換し
ないといけません。当方でも「最新の
    鬼車 を秀丸エディタの正規表現エンジンとして試したい」という要望に対して
h-tom さんからラッパー DLL の作成を
    推奨されたが、実際に DLL を作成するためにはこの「秀丸独自コード」を「真
正」の Unicode バイトシーケンスに
    変換する処理を実装しなければならない、という問題に遭遇した次第です。
   
    そこで申し上げるご要望として、秀丸エディタ本体が内部で使用しているロジッ
クにアクセスする公開 API を新設する、
    という形で「秀丸独自コード」<=>「真正の Unicode コードポイント」の相互変
換関数を、「DLL 側から秀丸エディタの
    関数呼び出し」用関数 ( hidemaru.exe 自身の Hidemaru_**** 関数 ) としてご
用意いただければ大変助かります。
   
    あくまで、秀丸エディタ本体が内部で行っている「秀丸独自コード」<=>「真正
の Unicode コードポイント」の相互変換の
    機能を外部から利用可能にするだけの関数です。こうすれば、御社が非公開にし
たい「秀丸独自コード」の仕様を
    隠ぺいしたまま、正規表現 DLL の開発者などへ相互変換の手段を提供できるよ
うになります。
   
    これが実現できれば、正規表現 DLL の開発者などが「秀丸独自コード」の仕様
を自力で解析して DLL などに実装する手間は
    もちろん、自力解析したとはいえ「秀丸独自コード」の仕様を記述したソース
コードを開発者が非公開にせざるを得なくなる
    問題も解決するはずです。


2.  上記 1. のご要望が実現不可能であった場合、でるもんた・いいじま さんが提
案したよう「秀丸独自コード」<=>
    「真正の Unicode コードポイント」の相互変換処理を自力で作成しないといけ
ません。
   
    そのためには、この「秀丸独自コード」と「真正の Unicode コードポイント」
の関係性を、でるもんた・いいじま さんが
      https://www.maruo.co.jp/hidesoft/2/x39752_.html#39755
    で提示された関数を用いて 1 文字ずつ調べて、相互変換の計算式を導出する
「解析作業」が必要になります。
   
    でるもんた・いいじま さん曰く、
    > UTF-8とよく似た、割と簡単な換算式で計算しているはずです。
    とのことですが、はたして実際の解析作業は簡単に済むものなのでしょうか。
   
    実際に解析作業を始めたら「仕様が想像以上に複雑で何週間も解析に掛かりっき
り」という状態は避けたいです。


3.  上記 2. の「秀丸独自コード」の仕様の自力解析が成功した場合、これを用いて
「秀丸独自コード」<=>
    「真正の Unicode コードポイント」の相互変換処理を実装した 鬼雲 のラッ
パー DLL などのソースコードを、そのまま
    GitHub などで公開してもよいのでしょうか。
   
    それとも相互変換処理の部分だけはソースコード非公開の別 DLL などどしない
といけないのでしょうか。
   
    h-tom さんは hmonig.dll に自力解析 ? した変換処理を実装していることを理
由にソースコードを非公開にしていますが、
    実際には公開可能だったのか、それとも本当に非公開にしないといけなかったの
か、当方では分かりかねるため、正しい見解の
    公表をお願い申し上げます。


以上の通り、1. が要望、2. と 3. が質問となっております。どうかよろしくお願い
申し上げます。



[ ]
RE:39771 正規表現DLLに検索文字列などとNo.39772
秀まるお2 さん 22/05/24 11:16
 
 要約させていただくと・・・変換用のライブラリ(DLL)があるといいって話です
よね。

 どんな関数があるといいか書いていただけるとなおありがたいのですが、どんなも
んでしょ?

    UINT WINAPI HidemaruText2Utf8( UINT codepage, const char* pszHidemaruTex
tInput, int cbHidemaruText
                     , char* pszUtf8Buffer, int cchUtf8Buffer );

    UINT WINAPI Utf82HidemaruText( UINT codepage, const char* pszUtf8Text, i
nt cbUtf8Text
                     , char* pszHidemaruTextBuffer, int cchHidemaruTextBuffe
r );

    UINT WINAPI HidemaruText2Unicode( UINT codepage, const char* pszHidemaru
TextInput, int cbHidemaruText
                     , WCHAR* pszUnicodeBuffer, int cchUnicodeBuffer );

    UINT WINAPI Unicode2HidemaruText( UINT codepage, const WCHAR* pszUnicode
Input, int cchUnicodeInput
                     , char* pszHidemaruTextBuffer, int cbHidemaruTextuffer );

 みたいなのとか。

[ ]
RE:39772 正規表現DLLに検索文字列などとNo.39774
fzok4234 さん 22/05/24 12:21
 
行き違いになりましたが、別 DLL にするよりかは hidemaru.exe 本体の「DLL側から
秀丸エディタの関数呼び出し」
  https://help.maruo.co.jp/hidemac/html/200_Dll_Api.html
に関数を追加する形がよいのでは、と思います。

実装としては、hidemaru.exe 自体が内部で使用している変換ロジックを、外部から
呼び出せるようにするだけの
関数を追加する方式です。hidemaru.exe 本体と別 DLL とで同じロジックの実装を二
重にしてしまうと、保守管理の
コストの増大はもちろん、一方のアップデートともう片方のアップデートの内容が食
い違うバグの原因に
なりかねないからです。

入出力の「真正」の Unicode エンコードは「 BOM 付きの UCS-4 」または、「 BOM
無しのリトルエンディアン UCS-4 」の
1 種類だけでよいと思います。UCS-4 から UTF-8 や UTF-16 などへの変換は状況に
合わせてユーザーが自由に行う
ものとします。UCS-4 なら 1 文字 4byte 固定でプログラムから扱いやすくなると考
えました。



[ ]
RE:39774 正規表現DLLに検索文字列などとNo.39775
こみやんま さん 22/05/24 17:12
 
UCS-4 のインターフェイスでは扱いにくいのでは...
他と関数と合わせる意味でも、wchar_t に併せておいていいと思います。

C++でもC#にかぎらず、VC++で扱う言語系なら暗黙の変換やアトリビュートが効く
シーンが多くてwchar_tの方が俄然あつかいやすいはずです。

[ ]
RE:39775 正規表現DLLに検索文字列などとNo.39776
秀まるお2 さん 22/05/24 17:58
 
 僕もよく分かってないのですが、普通にC言語なりC++言語なりでWindows用のソフ
トウェア開発するなら、WCHARやLPCWSTRの型で文字/文字列を扱うのが普通であって、
UCS-4とかなんとか、難しいことを言われても僕もどうしたらいいのかよく分からな
いです。

 秀丸エディタ内部の文字列は、普通にcharの配列になってます。それとユニコード
(LPWSTRとか)の間の変換ってことでいいですよね?

[ ]
RE:39776 正規表現DLLに検索文字列などとNo.39777
秀まるお2 さん 22/05/24 18:16
 
 一応簡単に内部のデータ構造を説明させていただきますと・・・

 内部の文字列は基本charの配列(普通のクラシックなC言語の文字列)になってま
して、Shift-JISそのまま(いわゆるMBCS文字列)が基本です。そして、Shift-JIS範
囲外の文字がある場合、たとえばそれがwchって値だったとすると、それを以下の
ルールで4バイトに変換します。

 1バイト目 ... \x1Aの文字。
 2バイト目 ... 0x80 + LOBYTE(wch)
 3バイト目 ... 0x80 + HIBYTE(wch)
 4バイト目 ... ((wUni & 0x80) >> 7) + ((wUni & 0x8000) >> 14) + 4 + nZenkaku

 でして、上記の「nZenkaku」は、全角文字なら8、そうでないなら0って値になりま
す。

 全角文字かどうかは別途ユニコード範囲のマップをもっててそれで決めています。

[ ]
RE:39777 正規表現DLLに検索文字列などとNo.39778
秀まるお2 さん 22/05/24 18:31
 
 4バイト目 ... ((wch & 0x80) >> 7) + ((wch & 0x8000) >> 14) + 4 + nZenkaku

 の間違いでした。

 秀丸メールの中では\x1Aで始まる4バイトのデータを「STARTUNI」と呼んでまして、

#define IsSTARTUNI_inline( p ) ( (*(DWORD*)(p) & 0xF4808000) == 0x04808000 )

 ってマクロでそれかどうか判定します。

WCHAR inline GetUnicodeInText( char* pchSrc ) {
    return MAKEWORD( (pchSrc[1] & 0x7F | ((pchSrc[3] & 0x01) << 7)),
                    (pchSrc[2] & 0x7F | ((pchSrc[3] & 0x02) << 6)) );
}

 って関数でWCHARに変換するだけです。

 秀丸エディタの内部テキストをユニコードに変換するのは上記のロジックで簡単に
出来ます。

 逆方向にするなら全角文字かどうかの判定が必要でして、それはライブラリが無い
と対応できないと思います。HmJre.dllの代替品を作るだけなら上記のロジックが分
かってるだけで簡単に対応できると思います。ライブラリも不要です。

 この辺サクっと理解できるならいいですが、ちんぷんかんぷんってことでしたら、
難しいことはやめた方がいいんじゃないかと思います。デバッグの手伝いも僕はやる
つもりはありませんし、プログラミングに関係することに長文で質問されるだけでも、
それを読むだけでも大変なので、勘弁してほしい所です。

[ ]
RE:39778 正規表現DLLに検索文字列などとNo.39779
秀まるお2 さん 22/05/24 18:40
 
 今さらながら思ったんですが、HmJre.dllの代替品を作るって話でしたっけか?
 (という、根本的な所に戻ってしまうのですが)

 もしそういうことでしたら、大変ハードルが高いです。

 参考資料として、HmJre.dllの秀丸エディタとやりとりしてるインタフェース部分
のソースコードだけならお渡ししてもいいです。メールにて「xxxxx@mitene.or.jp」
に連絡くれれば返信します。

 正規表現の処理をしてる本体ソースコードはお渡しできません。または、渡ししし
たソースコードの中で果たして何をしてるのかは、特にちゃんとしたドキュメントも
書いてないし、質問されてもお返事しません。自分で考えて分からなかったらあきら
めてもらうしかありません。

 そういう条件(質問一切不可)でならソースコードをお渡しします。

 たぶんそういうことなら変換用のライブラリは不要です。


---以下の内容はコミュニテックス会議室システムにより付加されました。
本文中のメールアドレスは伏せ字に変換されました。伏せ字にしたくない場合
はメールアドレスを""で囲んで書き込んでください。

[ ]
RE:39771 正規表現DLLに検索文字列などとNo.39780
h-tom さん 22/05/24 19:05
 
h-tom です。

いまさら必要ないでしょうが、回答しておきます。
>    h-tom さんは hmonig.dll に自力解析 ? した変換処理を実装していることを理
>由にソースコードを非公開にしていますが、
>    実際には公開可能だったのか、それとも本当に非公開にしないといけなかった
>のか、当方では分かりかねるため、正しい見解の
>    公表をお願い申し上げます。

リバースエンジニアリングなんてしてませんよ。
https://log.maruo.co.jp/turukame/turukame_2/x0901584.html に
>  もし内部的なユニコード文字についての情報がどうしても必要でしたら、それ
> はそれで個別に教えて差し上げることは出来るので、メールで連絡いただきたい
> と思います。
とあるので、公表しないという条件で教えてもらっただけです。

ちなみに、
> 公開したときに別のユーザーから
>   「なぜ『秀丸独自コード』の仕様を非公開にするのか ?」
> と問い詰められる事態となることは火を見るよりも明らかです。
という部類の問い合わせは、今まで一切受けたことはありません。

[ ]
RE:39779 正規表現DLLに検索文字列などとNo.39781
でるもんたいいじま さん 22/05/24 19:12
 
いいじまです。

> 今さらながら思ったんですが、HmJre.dllの代替品を作るって話でしたっけか?
> (という、根本的な所に戻ってしまうのですが)

正確には、代替のDLLを丸ごと作るのではなくて、既存のUTF-8ベースの正規表現ライ
ブラリを呼び出すためのラッパーを作りたい、という話ですね。

なので、置換結果のUTF-8文字列を0x1Aエスケープの文字列に戻す際に、全角半角フ
ラグのテーブルが必要になるのではと思います。
(秀丸側で結果を受け取ってフラグの訂正を行っていれば話は別ですが…。)

> 参考資料として、HmJre.dllの秀丸エディタとやりとりしてる
> インタフェース部分のソースコードだけならお渡ししてもいいです。
> メールにて「"xxxxx@mitene.or.jp"」に連絡くれれば返信します。

> ---以下の内容はコミュニテックス会議室システムにより付加されました。
> 本文中のメールアドレスは伏せ字に変換されました。伏せ字にしたく
> ない場合はメールアドレスを""で囲んで書き込んでください。

落ち着いてください^^

[ ]
RE:39779 正規表現DLLに検索文字列などとNo.39782
秀まるお2 さん 22/05/24 19:15
 
 すみません。メールアドレスは"maruo@mitene.or.jp"です。

[ ]
RE:39776 正規表現DLLに検索文字列などとNo.39783
fzok4234 さん 22/05/24 19:16
 
一応、UCS-4 ( UTF-32 ) は普通の文字もサロゲートペアも関係なく 1 文字が 1 個
の 32bit 整数で
固定サイズとなるため、文字種によって byte 数が変わる UTF-8 や サロゲートペア
が 2 文字扱いに
なる UTF-16 よりも扱いやすいのでは、と考えたからです。

.NET Framework 4.8 以下や一昔前の C/C++ とかの既存の古典的な処理系で扱いやす
くするためには、
.NET の System.String や C/C++ の LPWSTR の実体である UTF-16LE 一択でよいと
思います。

ちなみに、鬼車 では
  https://github.com/kkos/oniguruma/blob/master/doc/API.ja#L104
のように UTF-16 、UTF-8 、UTF-32 の全部を受け付けています。



[ ]
RE:39781 正規表現DLLに検索文字列などとNo.39784
秀まるお2 さん 22/05/24 19:20
 
> なので、置換結果のUTF-8文字列を0x1Aエスケープの文字列に戻す際に、全角半角
>フラグのテーブルが必要になるのではと思います。

 そういう質問を仮にソースコード提供相手から質問されても、お返事はしない、と
いう前提になります。

[ ]
RE:39776 正規表現DLLに検索文字列などとNo.39785
でるもんたいいじま さん 22/05/24 19:26
 
いいじまです。

> 僕もよく分かってないのですが、普通にC言語なりC++言語なりで
> Windows用のソフトウェア開発するなら、WCHARやLPCWSTRの型で
> 文字/文字列を扱うのが普通であって、UCS-4とかなんとか、
> 難しいことを言われても僕もどうしたらいいのかよく分からないです。

WindowsとJavaScriptの文字コードはUTF-16ですね。

Windows上のC言語の場合、そもそも言語仕様として wchar_t と unsigned short が
等価で、それをふまえてヘッダファイルで
  typedef wchar_t WCHAR, *LPWSTR, const *LPCWSTR;
のように定義されています。

Linuxあたりだと wchar_t は符号つき32bitで、U+10000以上の文字もコードポイント
1つで扱えます。

ちなみに余談ですが、wchar_t の符号の有無は ISO 規格では「実装依存」となって
いて、たとえばこんなコード:
  wchar_t c = -1;
  printf( "c = %lld\n", (signed long long)c );
を書くと違いが確認できます。

[ ]
RE:39776 正規表現DLLに検索文字列などとNo.39786
でるもんたいいじま さん 22/05/24 19:39
 
いいじまです。

すみません、ここの解説を忘れていました。

> UCS-4とかなんとか、難しいことを言われても

USS-4 は UTF-32 とほぼ同義です。
同様に、UCS-2 は UTF-16 とほぼ同義です。

細かい定義の違いはあるはずなのですが、私も理解していませんし、実務上は上記の
認識で問題ないと思います。

[ ]
RE:39778 正規表現DLLに検索文字列などとNo.39787
fzok4234 さん 22/05/24 20:23
 
詳細な情報の提供ありがとうございます。


> 1バイト目 ... \x1Aの文字。

とのことですが、ASCII 制御文字の「置換 ( SUB ) 」の 0x1A 自体はどのように取
り扱っているのでしょうか。



[ ]
RE:39787 正規表現DLLに検索文字列などとNo.39788
でるもんたいいじま さん 22/05/24 21:20
 
でるもんた・いいじまです。
サイトー企画さんはもうこの時間には店じまいかな?

> > 1バイト目 ... \x1Aの文字。
> とのことですが、ASCII 制御文字の「置換 ( SUB ) 」の
> 0x1A 自体はどのように取り扱っているのでしょうか。

実際に実験してみては?
実験用の関数は、hidesoft.2:39755 で私からご提案済みです。

それを使って、
$s = dllfuncstr(#hMyDLL, "HexDumpA", "\x1A");
としてみてください。

理論上は「1A 9A 80 04」とエンコードして渡すことができるはずですが、果たして
実装はそうなっているどうか。

#まあそれをいうなら、ヌルバイトも内部的に 1A 80 80 04 として
#保存できるはずなんですが、さすがにそこまではやらない、
#というのが現在の方針のようです。

[ ]
RE:39783 正規表現DLLに検索文字列などとNo.39789
こみやんま さん 22/05/25 01:44
 

>.NET Framework 4.8 以下や一昔前の C/C++ とかの既存の古典的な処理系で扱いや
>すくするためには、
>.NET の System.String や C/C++ の LPWSTR の実体である UTF-16LE 一択でよいと
>思います。


後学のために知っておきたいのですが、
「Windows専用のdll」を作る環境上において、
「UCS-2やutf8」ではなく「UCS-4」の方が自然に文字列を取り扱える
メジャー言語 & メジャーフレームワークってなんですか?

(そういう想定の最近のメジャー環境なるものが存在するわけですよね?)


[ ]
RE:39788 正規表現DLLに検索文字列などとNo.39790
秀まるお2 さん 22/05/25 09:39
 
 \x1AのEOF制御文字自体が内部的にどうなってるかは、別に知らなくても一般ユー
ザーさんは困らないだろうし、どうしても知りたかったら調べる方法はあると思いま
す。

 その辺の内部の話1つ1つ全部質問されてたらたまったもんじゃないので、これ以
上は答えたくないです。サポート対象外ということでお願いします。

[ ]
RE:39789 正規表現DLLに検索文字列などとNo.39791
fzok4234 さん 22/05/25 10:58
 
最近の C/C++ ( C11 以降と C++11 以降 ) では標準で UTF-32 文字列を扱えるよう
です。
  char32_t c = U'a' ;
  const char32_t * s = U"abc" ;
というように、char32_t 型という 4byte 整数値を格納可能な型が用意され、プレフ
ィックス
U を付けたリテラルで UTF-32 文字列を表現します。



[ ]
RE:39791 正規表現DLLに検索文字列などとNo.39792
でるもんたいいじま さん 22/05/25 11:19
 
でるもんた・いいじまです。


> 最近の C/C++ ( C11 以降と C++11 以降 ) では標準で UTF-32 文字列を扱えるよ
>うです。

>   char32_t c = U'a' ;
>   const char32_t * s = U"abc" ;
> というように、char32_t 型という 4byte 整数値を格納可能な型が用意され、

> プレフィックス U を付けたリテラルで UTF-32 文字列を表現します。


ついでにいうと char16_t 型もあります。

ただ、char32_t や char32_t の実体が Unicode と明確に規定されたのは C++20 か
らで、それ以前は基本、どんなエンコーディングで文字列を保存するかは実装依存で
した。

極端な話、char16_t に Shift_JIS2004 エンコーディングの文字列を入れる処理系が
あってもよかったし、char32_t に GB18030 の文字列を入れる処理系があってもまた
然り、でした。


ただ実際には、この型名をサポートしている処理系ではすべて Unicode を採用して
いたため、C++20 では「いっそのことUnicodeに決め打ちしちゃおうよ」ということ
になったようです。


https://cpprefjp.github.io/lang/cpp11/utf8_string_literals.html
https://cpprefjp.github.io/lang/cpp20/make_char16t_char32t_string_literals_be_utf16_32.html

[ ]
RE:39791 正規表現DLLに検索文字列などとNo.39793
こみやんま さん 22/05/25 14:20
 
>最近の C/C++ ( C11 以降と C++11 以降 ) では標準で UTF-32 文字列を扱えるよう
>です。
> ......
>
本当に使っていますか?
変数にchar32_t で定義したは良いけど、結構身動き取りづらい感じになるかと思う
のですが。

だってC++20の段階で別エンコードへの変換関数が標準ライブラリに存在しないです
し(一旦搭載された版もあったが強く非推奨となった)
各ライブラリはそのchar32_tには全く対応してないですよ。


[ ]
RE:39793 正規表現DLLに検索文字列などとNo.39794
fzok4234 さん 22/05/25 20:18
 
> だってC++20の段階で別エンコードへの変換関数が標準ライブラリに存在しないですし
> (一旦搭載された版もあったが強く非推奨となった)
> 各ライブラリはそのchar32_tには全く対応してないですよ。

ここでいう「標準ライブラリ」とか「各ライブラリ」という用語は、文字列のコピー
の wcscpy_s とか
連結の wcscat_s というような、実際に char や WCHAR を文字列として加工や情報
取得するための
関数群を指しているようですね。

だとすれば、現時点でも ASCII と、 Shift-JIS などのマルチバイト文字と、UTF-16
LE と、コンパイル時切り替え
の LPTSTR のための 4 種類しか存在しません。

「ライブラリ」の意味を取り違えていたようで、大変失礼いたしました。


それから、

> (一旦搭載された版もあったが強く非推奨となった)

とのことですが、C++11 で標準搭載された codecvt という文字コード変換ライブラ
リが C++17 では非推奨となった
ようです。このため、C/C++ 環境での文字コード変換は
  https://qiita.com/benikabocha/items/e943deb299d0f816f161
とかで紹介されているように「自前で実装」するか、あるいは .Net の System.Text.
Encoder と System.Text.Decoder の
ようなマネージドコード用フレームワークを流用するなどしないと駄目なようです。



[ ]
RE:39794 正規表現DLLに検索文字列などとNo.39795
こみやんま さん 22/05/25 22:02
 
比較的古風印象を匂わせる関数群だけでなく、
cout系のbasic_ostreamはu32stringは対象外ですし
C++20で文字列を加工するためだけに入ったformatもu32stringは対象外ですし、
以前からあるstringstream系などもchar32_tは対象外ですので、(basic_stringstrea
mのテンプレートからchar32_tを利用したとしても動作はしないようになっている)
文字列の実践的な加工どころかコンソールへの表示すらままならないというのがu32s
tring型の実情です。

結局wstringとの相互変換しまくりになるだけだと気づき(しかも標準手段なし)、
すぐにwstringかもしくはstring型でutf8を想定して突っ込むスタイルに戻ると思い
ますね。

現在のマイクロソフトの試みからも
Windowsのシステムロケールの標準が
utf8へと移行する可能性は十分考えられるので、
将来日が当たるとすればそっちですかねぇ。

[ ]
RE:39777 正規表現DLLに検索文字列などとNo.39796
fzok4234 さん 22/05/26 16:56
 
> 1バイト目 ... \x1Aの文字。
> 2バイト目 ... 0x80 + LOBYTE(wch)
> 3バイト目 ... 0x80 + HIBYTE(wch)
> 4バイト目 ... ((wch & 0x80) >> 7) + ((wch & 0x8000) >> 14) + 4 + nZenkaku
> でして、上記の「nZenkaku」は、全角文字なら8、そうでないなら0って値になりま
>す。

上記の中の加算演算子「+」は、ビット論理和の「|」の間違いのような気がしますが、
正確にはどうなのでしょうか。



[ ]
RE:39796 正規表現DLLに検索文字列などとNo.39797
秀まるお2 さん 22/05/26 17:41
 
> 上記の中の加算演算子「+」は、ビット論理和の「|」の間違いのような気がします
>が、
> 正確にはどうなのでしょうか。

 すみません。たしかにそのようでした。

void WriteUnicodeToText( WCHAR wUni, char* pszDest ) {
    *pszDest = '\x1A';
    WRITEWORD( (WORD*)(pszDest + 1), wUni | 0x8080 );
    UINT nZenkaku = GetZenkakuFlag( wUni );    ... 0か8の値
    pszDest[3] = ((wUni & 0x80) >> 7) + ((wUni & 0x8000) >> 14) + 4 + nZenkaku;
}

 みたいになってました。

[ ]
RE:39797 正規表現DLLに検索文字列などとNo.39798
こみやんま さん 22/05/26 20:07
 
>> 上記の中の加算演算子「+」は、ビット論理和の「|」の間違いのような気がしま
>すが、
> ......
> みたいになってました。
エンコード・デコードともに「全文字」現在の秀丸エディタでやってる処理と同じに
なると思われます。
(手前で保持していた完全マップとの全一致を確認しました)

[ ]
RE:39796 正規表現DLLに検索文字列などとNo.39799
でるもんたいいじま さん 22/05/26 23:17
 
でるもんた・いいじまです。

> 上記の中の加算演算子「+」は、ビット論理和の
> 「|」の間違いのような気がしますが、
> 正確にはどうなのでしょうか。

意味としてはビット論理和ですが、今回の場合は加算を使っても結果は全く変わりま
せん。
なぜなら、どのビットにも「1+1」の計算は一切存在しないから。

ついでにいうと、どんなCPUでもほぼ例外なく、加算とビット論理和は同じ速度です。
多倍長演算や浮動小数点など例外もありますが、少なくとも「固定ビット数の整数レ
ジスタ間で」という前提ではぴったり同じ速度です。

…DLLを作りたいと言っていて、今までずっと大風呂敷を広げてきたからには、その
くらいは説明されなくても当然理解できて然るべきです。もし理解できないのであれ
ば、貴殿のDLLにはほぼ間違いなくセキュリティホールが紛れ込みますから、被害が
拡大する前にとっとと諦めていただきたいです。

[ ]
RE:39799 正規表現DLLに検索文字列などとNo.39800
こみやんま さん 22/05/26 23:46
 
>意味としてはビット論理和ですが、今回の場合は加算を使っても結果は全く変わり
>ません。
>なぜなら、どのビットにも「1+1」の計算は一切存在しないから。



BYTE a = 0x80 + 0x80
BYTE b = 0x80 | 0x80

型に収まる収まらないはおいておいたとしいても、普通に結果は変わるのでは?

[ ]
RE:39800 正規表現DLLに検索文字列などとNo.39801
でるもんたいいじま さん 22/05/27 01:25
 
でるもんた・いいじまです。


> >意味としてはビット論理和ですが、今回の場合は加算を使っても結果は全く変わ
>りません。

> >なぜなら、どのビットにも「1+1」の計算は一切存在しないから。

>
> ?

> BYTE a = 0x80 + 0x80
> BYTE b = 0x80 | 0x80
> 型に収まる収まらないはおいておいたとしいても、普通に結果は変わるのでは?


落ち着いてください。

「今回の場合は」と但し書きをつけてあります。


再掲
> 4バイト目 ... ((wch & 0x80) >> 7) + ((wch & 0x8000) >> 14) + 4 + nZenkaku

(wch & 0x80) は0か0x80です。それを7つシフトしていますので0か1です。

(wch & 0x8000) は0か0x8000ですね。シフトしたら0か2です。

それに4を足す。

nZenkakuは0か8。

すべて別々のビットに1が存在するので、+ でも | でも変わりません。


BYTE a = 0xAA + 0x55;
BYTE b = 0xAA | 0x55;
どちらも同じ結果ですし、偶然じゃなくてわざとそうなるように0xAAと0x55を選んで
いる、ということもお分かりいただけますよね?

[ ]
RE:39801 正規表現DLLに検索文字列などとNo.39802
こみやんま さん 22/05/27 02:00
 
> 2バイト目 ... 0x80 + LOBYTE(wch)
> 3バイト目 ... 0x80 + HIBYTE(wch)

+ と | で結果が同じだとは思えないですけどねぇ。


[ ]
RE:39802 正規表現DLLに検索文字列などとNo.39803
こみやんま さん 22/05/27 06:23
 
もう少し噛み砕きますが、

posted by fszok4234
-------------------------------------------
> 1バイト目 ... \x1Aの文字。
> 2バイト目 ... 0x80 + LOBYTE(wch)
> 3バイト目 ... 0x80 + HIBYTE(wch)
> 4バイト目 ... ((wch & 0x80) >> 7) + ((wch & 0x8000) >> 14) + 4 + nZenkaku
> でして、上記の「nZenkaku」は、全角文字なら8、そうでないなら0って値になりま
>す。

上記の中の加算演算子「+」は、ビット論理和の「|」の間違いのような気がしますが、
正確にはどうなのでしょうか。
-------------------------------------------


とうぜんfszok4234さんの投稿は、4バイト目だけではなく、
2バイト目と3バイト目も含めた話としての指摘ですよね。


postd by でるもんた・いいじま
-------------------------------------------
> 上記の中の加算演算子「+」は、ビット論理和の
> 「|」の間違いのような気がしますが、
> 正確にはどうなのでしょうか。

意味としてはビット論理和ですが、今回の場合は加算を使っても結果は全く変わりま
せん。
なぜなら、どのビットにも「1+1」の計算は一切存在しないから。
-------------------------------------------


4バイト目は別として
2バイト目と3バイト目は0x0〜0xFFを取るBYTE値になるため、
「+」と「|」で結果がかわるのではないですか?
ということで私は2バイト目と3バイト目にそっくりな計算となる

posted by こみやんま
------------------------------------------
BYTE a = 0x80 + 0x80
BYTE b = 0x80 | 0x80
------------------------------------------

を例として出したのですが...


でるもんた・いいじま さんは、1バイト目〜4バイトまで含めた全ての計算結果に
おいて
「+」にしたものと「|」にしたもので変化しないという主張でよろしいんですかね?


それともどこかの投稿で「4バイト目だけのついて話をしよう」みたいな
話題でもあったんでしょうか。

[ ]
RE:39801 正規表現DLLに検索文字列などとNo.39804
fzok4234 さん 22/05/27 07:27
 
> 今回の場合は加算を使っても結果は全く変わりません。

確かに「今回の場合」に限っては、計算アルゴリズム上「|」を「+」に変えても結果
は同じかもしれません。
だが、人間が読んでみて ?? となるようなトリッキーなコードは書くべきではないと
思います。多少コード量が
増えたり実行速度が低下したりしても、保守管理のしやすさの面から人間が理解しや
すいコードを書いた方が
よいと思われます。



[ ]
RE:39778 正規表現DLLに検索文字列などとNo.39805
fzok4234 さん 22/05/27 08:31
 
でるもんた・いいじま さんの助言をもとに、文末に掲載の検証用の DLL とマクロで
いろいろテストを
行っているのですが、実行結果から「秀丸独自コード」の挙動を確認したところ、実
際にこれを正規表現 DLL などで
処理するうえでどのように対処したらよいのか分からない点がございます。


1.  Shift-JIS で二重定義された文字についてです。例えば、記号の「≒」( U+2252
 ) は、Shift-JIS 上は
    0x81E0 と 0x8790 で二重に定義されているのですが、マクロの文字列リテラル
として直接 @"≒" と
    した場合は「秀丸独自コード」は 0x81E0 のほうを踏襲して 81 E0 となります。
一方、char 関数を
    使って char( 0x8790 ) と書いた場合には記述通りに 87 90 となります。
   
    しかし、両方とも Unicode にすると同じ U+2252 になって、これを元の「秀丸
独自コード」に戻す時には
    どちらだったのか分からなくなっています。この 2 つを明確に区別する必要が
ある場合はどうすれば
    よいのでしょうか。


2.  制御文字 \x1A で始まる一部の Shift-JIS 文字列についてです。例えば、制御
コード交じりの半角カナの
    「\x1Aツチ\x0F」を「秀丸独自コード」にすると、1A C2 C1 0F となります。一方、
ハングルの「&#49602;」( U+C1C2 ) の
    「秀丸独自コード」も同じく 1A C2 C1 0F となります。
   
    当然、この 2 つは明確に区別されなければならないのですが、一度「秀丸独自
コード」にしてしまうと全く
    区別がつかなくなってしまいます。この場合はどのように対処すればよいのでし
ょうか。
   
    なお、秀丸エディタの検索ダイアログでは HmJre.dll および hmonig.dll とも
に、パターン「&#49602;」が本文の
    「\x1Aツチ\x0F」にマッチしたり、逆にパターン「\x1Aツチ\x0F」が「&#49602;」に
マッチするようなことはありませんでした。
    これらの DLL ではいったいどうやって 1A C2 C1 0F の元の文字列を判別してい
るのか知りたいです。



// -------------------------------- HexDump.dll ----------------------------
----
// Visual Studio 2019 にて C17 としてビルド。
// ここでは size_t の加算や乗算での整数オーバーフロー対策はしていません。
// メモリリーク防止のため、マクロ上で freedll する前に Clear() 関数を実行す
る必要があります。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>

wchar_t *   hexString           = ( (wchar_t *) NULL )  ;
wchar_t     emptyHexString[ 1 ] = { L'\0' }             ;

wchar_t *   WINAPI getHexString(    void )              ;
void        WINAPI setHexString(    void * , size_t )   ;
void        WINAPI clearHexString(  void )              ;

wchar_t * WINAPI getHexString() {
    return ( ( (wchar_t *) NULL ) == hexString ) ? emptyHexString : hexString ;
}

void WINAPI setHexString(
        void *  byteData
    ,   size_t  byteDataLength
) {
    clearHexString() ;
    if ( NULL == byteData ) { return ; }
   
    size_t  hexDigitWidth   = ( (size_t) 2 )    ;
    size_t  hexSpaceWitdh   = ( (size_t) 1 )    ;
    size_t  hexItemWidth    = ( hexDigitWidth + hexSpaceWitdh ) ;
   
    hexString = ( (wchar_t *) malloc(
            ( ( byteDataLength * hexItemWidth ) + ( (size_t) 1 ) )
        *   sizeof( wchar_t )
    ) ) ;
   
    unsigned char * byteDataStart   = ( (unsigned char *) byteData )    ;
    wchar_t *       hexStringPtr    = hexString                         ;
    for ( size_t byteDataOffset = ( (size_t) 0 ) ; byteDataOffset < byteData
Length ; byteDataOffset ++ ) {
        swprintf_s(
                hexStringPtr
            ,   hexDigitWidth + ( (size_t) 1 )
            ,   L"%0*hhX"
            ,   (int) hexDigitWidth
            ,   * ( byteDataStart + byteDataOffset )
        ) ;
        hexStringPtr += hexDigitWidth ;
       
        ( * hexStringPtr ) = L' '       ;
        hexStringPtr += hexSpaceWitdh   ;
    }
   
    ( * hexStringPtr ) = L'\0' ;
}

void WINAPI clearHexString() {
    if ( ( (wchar_t *) NULL ) != hexString ) {
        free( (void *) hexString )      ;
        hexString = ( (wchar_t *) NULL )  ;
    }
}

BOOL WINAPI DllMain( HINSTANCE , DWORD , LPVOID ) ;
__declspec( dllexport ) void    __cdecl STARTUNIMACRO ( void )      ;
__declspec( dllexport ) INT_PTR __cdecl ExecuteAscii(   char * )    ;
__declspec( dllexport ) INT_PTR __cdecl ExecuteUnicode( WCHAR * )   ;
__declspec( dllexport ) WCHAR * __cdecl GetResult()                 ;
__declspec( dllexport ) INT_PTR __cdecl Clear()                     ;

BOOL WINAPI DllMain(
        HINSTANCE   hinstDLL
    ,   DWORD       fdwReason
    ,   LPVOID      lpReserved
) {
    switch ( fdwReason ) {
        case DLL_PROCESS_ATTACH : break ;
        case DLL_PROCESS_DETACH : break ;
        case DLL_THREAD_ATTACH  : break ;
        case DLL_THREAD_DETACH  : break ;
    }
   
    return TRUE ;
}

__declspec( dllexport ) void __cdecl STARTUNIMACRO () {}

__declspec( dllexport ) INT_PTR __cdecl ExecuteAscii(
        char *  inputString
) {
    setHexString(
            (void *) inputString
        ,       ( strlen( (const char *) (void *) inputString ) + ( (size_t)
 1 ) )
            *   sizeof( char )
    ) ;
   
    return (INT_PTR) TRUE ;
}

__declspec( dllexport ) INT_PTR __cdecl ExecuteUnicode(
        WCHAR * inputString
) {
    setHexString(
            (void *) inputString
        ,       ( wcslen( (const wchar_t *) (void *) inputString ) + ( (size
_t) 1 ) )
            *   sizeof( wchar_t )
    ) ;
   
    return (INT_PTR) TRUE ;
}

__declspec( dllexport ) WCHAR * __cdecl GetResult() {
    return (WCHAR *) (void *) getHexString() ;
}

__declspec( dllexport ) INT_PTR __cdecl Clear() {
    clearHexString() ;
   
    return (INT_PTR) TRUE ;
}


// -------------------------------- Test.mac --------------------------------

#defaultCompatibleMode = setcompatiblemode(
        0x00000003
    |   0x0000000C
    |   0x00000200
    |   0x00020000
    |   0x00080000
    |   0x00400000
    |   0x00800000
    |   0x04000000
    |   0x08000000
) ;
disablehistory
        0x00000001
    |   0x00000002
    |   0x00000004
    |   0x00000008
    |   0x00000010
    |   0x00000020
    |   0x00000040
;
disablebreak ;
#defaultTopY = screentopy ; #defaultLeftX = screenleftx ; disabledraw ; disa
bleinvert ;

#hexDump = loaddll( currentmacrodirectory + @"\HexDump.dll" ) ;
    #stringCount = 0 ;
    $title[ #stringCount ] = @"ASCII 範囲"              ;
    $string[ #stringCount ] = @"abcd"                                      
                      ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"Shift-JIS 範囲"          ;
    $string[ #stringCount ] = @"あいうえ"                                  
                      ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"Unicode 半角"            ;
    $string[ #stringCount ] = @"&#313;&#315;&#317;&#319;"                  
                                          ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"Unicode 全角"            ;
    $string[ #stringCount ] = @"&#8104;&#8105;&#8106;&#8107;"              
                                          ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"サロゲートペア"          ;
    $string[ #stringCount ] = @"&#120798;&#74245;"                          
                                   ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"合字"                    ;
    $string[ #stringCount ] = @"&#128105;&#127996;&#8205;&#128104;&#127997;&
#8205;&#128102;&#127996;&#8205;&#128103;&#127997;"                          
                                     ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"混合"                    ;
    $string[ #stringCount ] = @"a&#8104;&#313;あ&#120798;"                  
                                       ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"Shift-JIS の重複定義 1"  ;
    $string[ #stringCount ] = char( 0x81E0 ) + char( 0xED40 )              
                      ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"Shift-JIS の重複定義 2"  ;
    $string[ #stringCount ] = char( 0x8790 ) + char( 0xFA5C )              
                      ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"Shift-JIS の重複定義 3"  ;
    $string[ #stringCount ] = @"≒\"                                      
                      ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"不正サロゲート"          ;
    $string[ #stringCount ] = "\U0000DFDE" + @"a" + "\U0000D835" + @"b" + "\
U0000DFDE\U0000D835"  ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"Null 文字"               ;
    $string[ #stringCount ] = @"ab" + "\U00000000" + @"cd"                  
                      ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"秀丸独自コードと重複 1"  ;
    $string[ #stringCount ] = @"&#49602;&#49602;"                          
                                  ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"秀丸独自コードと重複 2"  ;
    $string[ #stringCount ] = "\x1A" + @"ツチ" + "\x0F\x1A" + @"ツチ" + "\x0F"  
                      ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"Unicode 未使用"          ;
    $string[ #stringCount ] = "\U00314000\U00314001\U00314002\U00314003"    
                      ;
    #stringCount = #stringCount + 1 ;
    $title[ #stringCount ] = @"Unicode 範囲外"          ;
    $string[ #stringCount ] = "\U00500000\U01000000\U10000000\U80000000"    
                      ;
    #stringCount = #stringCount + 1 ;
   
    #stringIndex = 0 ;
    while ( #stringIndex < #stringCount ) {
        call WriteLine @"[" + $title[ #stringIndex ] + @"]" ;
        call WriteLine @"String  = " + $string[ #stringIndex ]              
            ;
        #result = dllfuncw( #hexDump , @"ExecuteUnicode"    , $string[ #stri
ngIndex ] ) ;
        call WriteLine @"Unicode = " + dllfuncstrw( #hexDump , @"GetResult"
 )           ;
        #result = dllfunc(  #hexDump , @"ExecuteAscii"      , $string[ #stri
ngIndex ] ) ;
        call WriteLine @"Ascii   = " + dllfuncstrw( #hexDump , @"GetResult"
 )           ;
        call WriteLine @""  ;
       
        #stringIndex = #stringIndex + 1 ;
    }
#result = dllfuncw( #hexDump , @"Clear" ) ; freedll #hexDump ;

refreshoutline ;
enableinvert ; enabledraw #defaultTopY , #defaultLeftX ;
enablebreak ;
setcompatiblemode #defaultCompatibleMode ;
endmacro ;

WriteLine :
    insert $$1          ;
    insert "\U0000000A" ;
   
    return ;


// -------------------------------- 実行結果 --------------------------------

[ASCII 範囲]
String  = abcd
Unicode = 61 00 62 00 63 00 64 00 00 00
Ascii   = 61 62 63 64 00

[Shift-JIS 範囲]
String  = あいうえ
Unicode = 42 30 44 30 46 30 48 30 00 00
Ascii   = 82 A0 82 A2 82 A4 82 A6 00

[Unicode 半角]
String  = &#313;&#315;&#317;&#319;
Unicode = 39 01 3B 01 3D 01 3F 01 00 00
Ascii   = 1A B9 81 04 1A BB 81 04 1A BD 81 04 1A BF 81 04 00

[Unicode 全角]
String  = &#8104;&#8105;&#8106;&#8107;
Unicode = A8 1F A9 1F AA 1F AB 1F 00 00
Ascii   = 1A A8 9F 0D 1A A9 9F 0D 1A AA 9F 0D 1A AB 9F 0D 00

[サロゲートペア]
String  = &#120798;&#74245;
Unicode = 35 D8 DE DF 08 D8 05 DE 00 00
Ascii   = 1A B5 D8 06 1A DE DF 07 1A 88 D8 06 1A 85 DE 06 00

[合字]
String  = &#128105;&#127996;&#8205;&#128104;&#127997;&#8205;&#128102;&#12799
6;&#8205;&#128103;&#127997;
Unicode = 3D D8 69 DC 3C D8 FC DF 0D 20 3D D8 68 DC 3C D8 FD DF 0D 20 3D D8
66 DC 3C D8 FC DF 0D 20 3D D8 67 DC 3C D8 FD DF 00 00
Ascii   = 1A BD D8 06 1A E9 DC 06 1A BC D8 06 1A FC DF 07 1A 8D A0 04 1A BD
D8 06 1A E8 DC 06 1A BC D8 06 1A FD DF 07 1A 8D A0 04 1A BD D8 06 1A E6 DC 0
6 1A BC D8 06 1A FC DF 07 1A 8D A0 04 1A BD D8 06 1A E7 DC 06 1A BC D8 06 1A
 FD DF 07 00

[混合]
String  = a&#8104;&#313;あ&#120798;
Unicode = 61 00 A8 1F 39 01 42 30 35 D8 DE DF 00 00
Ascii   = 61 1A A8 9F 0D 1A B9 81 04 82 A0 1A B5 D8 06 1A DE DF 07 00

[Shift-JIS の重複定義 1]
String  = ≒\
Unicode = 52 22 8A 7E 00 00
Ascii   = 81 E0 ED 40 00

[Shift-JIS の重複定義 2]
String  = ≒\
Unicode = 52 22 8A 7E 00 00
Ascii   = 87 90 FA 5C 00

[Shift-JIS の重複定義 3]
String  = ≒\
Unicode = 52 22 8A 7E 00 00
Ascii   = 81 E0 FA 5C 00

[不正サロゲート]
String  = &#65533;ab&#65533;
Unicode = DE DF 61 00 35 D8 62 00 DE DF 35 D8 00 00
Ascii   = 1A DE DF 07 61 1A B5 D8 06 62 1A DE DF 07 1A B5 D8 06 00

[Null 文字]
String  = abcd
Unicode = 61 00 62 00 63 00 64 00 00 00
Ascii   = 61 62 63 64 00

[秀丸独自コードと重複 1]
String  = &#49602;&#49602;
Unicode = C2 C1 C2 C1 00 00
Ascii   = 1A C2 C1 0F 1A C2 C1 0F 00

[秀丸独自コードと重複 2]
String  = ツチツチ
Unicode = 1A 00 82 FF 81 FF 0F 00 1A 00 82 FF 81 FF 0F 00 00 00
Ascii   = 1A C2 C1 0F 1A C2 C1 0F 00

[Unicode 未使用]
String  = &#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;&#65533;
Unicode = 10 DC 00 DC 10 DC 01 DC 10 DC 02 DC 10 DC 03 DC 00 00
Ascii   = 1A 90 DC 06 1A 80 DC 06 1A 90 DC 06 1A 81 DC 06 1A 90 DC 06 1A 82
DC 06 1A 90 DC 06 1A 83 DC 06 00

[Unicode 範囲外]
String  = &#1048576;&#65472;&#65533;&#65472;&#65533;&#65472;&#65533;
Unicode = C0 DB 00 DC C0 FF 00 DC C0 FF 00 DC C0 FF 00 DC 00 00
Ascii   = 1A C0 DB 07 1A 80 DC 06 1A C0 FF 07 1A 80 DC 06 1A C0 FF 07 1A 80
DC 06 1A C0 FF 07 1A 80 DC 06 00



[ ]
RE:39805 正規表現DLLに検索文字列などとNo.39806
こみやんま さん 22/05/27 09:00
 
さすがにfzok4234さんはワザとやってるのかな?

posted by 秀まるお2
----------------------------------------------------------------------------
---------------
\x1AのEOF制御文字自体が内部的にどうなってるかは、別に知らなくても一般ユー
ザーさんは困らないだろうし、どうしても知りたかったら調べる方法はあると思いま
す。
その辺の内部の話1つ1つ全部質問されてたらたまったもんじゃないので、これ以上
は答えたくないです。サポート対象外

プログラミングに関係することに長文で質問されるだけでも、それを読むだけでも大
変なので、勘弁してほしい所です。
----------------------------------------------------------------------------
---------------

[ ]
RE:39806 正規表現DLLに検索文字列などとNo.39807
fzok4234 さん 22/05/27 09:35
 
一応、ちゃんと検証用 DLL を用意して自分で調べることができる範囲内は挙動を把
握したつもりです。
そのうえで、検証用 DLL の結果から新たに出てきた問題点への対処法を素直に尋ね
ただけです。
この対処法が分からないと、「秀丸独自コード」<=> Unicode の変換の実装で躓く原
因になり得ます。


[ ]
RE:39807 正規表現DLLに検索文字列などとNo.39808
秀まるお2 さん 22/05/27 09:52
 
 HmJre.dllのソースコードの、特に正規表現の処理についての核心部分を除去して
それを提供しようと思います。それを使ってテストしてもらったらいいんじゃないか
と思います。

 うちのホームページにアップロードしようと思います。アップロードできたらまた
連絡させていただきます。

 疑問に思っておられることは、もしかしたら秀丸エディタ的にバグっててうまく処
理できてない可能性もあるかもしれません。もしバグってることが間違いなさそうで
したら、逆に僕にアドバイスお願いしたいです。

[ ]
RE:39808 正規表現DLLに検索文字列などとNo.39809
fzok4234 さん 22/05/27 09:57
 
> HmJre.dllのソースコードの、特に正規表現の処理についての核心部分を除去して
>それを
> 提供しようと思います。それを使ってテストしてもらったらいいんじゃないかと思
>います。
>
> うちのホームページにアップロードしようと思います。アップロードできたらま
>た連絡させていただきます。
>

手厚い対応ありがとうございます。


[ ]
RE:39802 正規表現DLLに検索文字列などとNo.39810
でるもんたいいじま さん 22/05/27 09:57
 
いいじまです。

> > 2バイト目 ... 0x80 + LOBYTE(wch)
> > 3バイト目 ... 0x80 + HIBYTE(wch)
>
> + と | で結果が同じだとは思えないですけどねぇ。

あ、失礼しました。見落としていました。

秀まるおさんから開示されたコードでは2・3バイト目は
> WRITEWORD( (WORD*)(pszDest + 1), wUni | 0x8080 );
となっていて、実際に加算ではなく論理和を使っていますね。

4バイト目は加算でも結果は変わりません。

[ ]
RE:39804 正規表現DLLに検索文字列などとNo.39811
でるもんたいいじま さん 22/05/27 10:05
 
いいじまです。

> 人間が読んでみて ?? となるようなトリッキーなコードは
> 書くべきではないと思います。多少コード量が増えたり
> 実行速度が低下したりしても、保守管理のしやすさの面から
> 人間が理解しやすいコードを書いた方がよいと思われます。

一般論としては全く同意です。

あるいは、「コード量が増えたり実行速度が低下したり」の度合いが「多少」ではな
く無視できないレベルになる場合は、インライン関数などでカプセル化するのがスジ
です。

ただ今回の4バイト目に関しては、別々のビット同士の重ね合わせの際に、論理和に
代えて加算を使うのは割と広く行われていると個人的には認識しています。

たとえばVisualBasicの
MsgBox "Are you okay?", vbOKCancel + vbInformation + vbDefaultButton2 + vbSy
stemModal
なんていう例(手元のExcelで書いてみました)では、内部の挙動としては論理和(o
r)ですけど、それぞれのキーワードの意味を考えると個人的にはここには「or」で
はなく「+」と書きたくなります。

[ ]
RE:39808 正規表現DLLに検索文字列などとNo.39812
fzok4234 さん 22/05/27 10:06
 
質問 2. の \x1A 始まりの半角カナの件ですが、hmonig.dll では正しく区別できて
いるようです。
h-tom さんに何か特別な対処法を提供されましたでしょうか。


[ ]
RE:39805 正規表現DLLに検索文字列などとNo.39813
でるもんたいいじま さん 22/05/27 12:32
 
いいじまです。

既にご存知の内容も多々あるかと思いますが、少し丁寧に書いてみます。

> 1.  Shift-JIS で二重定義された文字についてです。
> 例えば、記号の「≒」( U+2252 ) は、Shift-JIS 上は
> 0x81E0 と 0x8790 で二重に定義されているのですが、
....
> しかし、両方とも Unicode にすると同じ U+2252 になって、
> これを元の「秀丸独自コード」に戻す時にはどちらだったのか
> 分からなくなっています。この 2 つを明確に区別する必要が
> ある場合はどうすればよいのでしょうか。

これは「そもそも U+2252 に統合してはいけない」が答えです。

0x81E0 は JIS X0208:1983 で追加された文字です。
0x8790 のほうは、それより前に NEC が独自採録した文字で、過去のデータとの互換
性のためだけに現在ここに残されています。

Microsoftの変換ルールでは、こういうベンダー独自文字については Unicodeの roun
d-trip conversion の対象外としているようです。明確に言明したものを読んだわけ
ではありませんが、実際の実装では単一のコードポイントに統合されます。

なので、Windows API の MultiByteToWideChar() は 81 E0 と 87 90 をどちらも U+
2252 にマップし、WideCharToMultiByte() は U+2252 を無条件で 81 E0 に戻します。

同様のことが 0xFA40〜0xFC4B と 0xED40〜0xEFFC の間にも言えて、前者はIBMが追
加した文字、後者はNECが「内部的に 7bit JIS コードを使っている関係上、94×94
の範囲内に納めたい」という理由で追加したコードポイントです。

Unicodeに変換する際にはすべて統合されますし、Shift_JIS(というかCP932)に戻
す際には「0x81xx(JIS83で採録)→0x87xx(NEC機を中心に普及して、最終的に JIS
 X0213:2000 で公認)→0xFAxx〜0xFCxx」の順で選択されます。0xEDxx〜0xEFxx を
使うのは ISO-2022-JP-MS などにマッピングする場合のみです。

こういうものをどうしても区別したい、でもUnicodeベースで処理したい、という場
合は、重複と分かっている文字を自前でUnicodeの私用領域にマップするしかありま
せん。これは秀丸に限らず、あるいは日本語だけに限らず、Windowsのレガシー文字
セットとUnicodeの相互変換を行うアプリ全般に当てはまります。

具体的にどこのコードポイントが重複なのかは、charmap.exeで何か適当な日本語フ
ォント(たとえばMS ゴシック)を選び、「文字セット:Windows日本語」を指定し
て1文字ずつステータスバーの表示を確認していけばすぐにわかります。CP932の場合、
0xED40〜0xEFFCの全部、0x87xxの末尾にある一部の数学記号、0xFAxxの非漢字の一部、
が「ラウンドトリップしない文字」に該当します。

具体的な実装としては、0xED40〜0xEFFCは先頭バイトで機械的に判定してそのまま U
+ED40〜U+EFFC あたりにマップ、0x87xxと0xFAxxは該当の文字だけをリストアップし
たハッシュで相互変換、というのが手っ取り早いと思います。

☆ ☆ ☆

> 2. 制御文字 \x1A で始まる一部の Shift-JIS 文字列についてです。

既に秀まるおさんから回答をいただいていますが、これについてもコメントを。

そもそも、なぜ 0x1A というコードが使われているのか分かりますか?
これはかつて、ここまででテキストデータの終わり、という意味だったのです。
今でも、copy con xxx.txt とか wget -i con とかの際には最後に Ctrl+Z を打ちま
すよね。

あるいはこんなテスト
  > perl -e "print qq'ab\n\x{1a}cd\n';" > 0x1A.txt
  > type 0x1A.txt
  > perl -e "open FD, '< 0x1A.txt'; print join('',<FD>);"
をしてみても、typeコマンドでは1行目だけしか出力されません。一方で、Perlでope
n()したケースでは最後まで出ます。それ以外の各種プログラミング言語でも、テキ
ストモードでファイルを読み込んでいて0x1Aが出現したらその先のデータは全部ゴミ、
とみなして打ち止めにする場合があります。

この仕様は、Windowsの祖先のMS-DOSの、そのまた祖先のCP/MというOSの制約で、デ
ィスク上のファイルが128バイト単位でしか読み書きできなかったことに由来します。
テキストデータの場合は当然、128バイトに満たない端数が出ますので、その端数部
分をどうやって記録するかが問題になります。「最大127バイトを0x00で綺麗に埋め
る」は当時としては少々コストが高いですよね。

で、特定の1バイトをデータの終端として使うと決めた際に、ディスク上に保存する
都合だけ考えれはたとえば0x00でもよかったのですが、当時はまだCP/Mの世界でC言
語はほとんど使われていませんでしたし、当時の通信回線で0x00は特別な意味を持っ
ていたのかもしれませんし、あるいは、キーボードから入力する際に Ctrl+@ は少々
面倒、という判断が働いたのかもしれません。

(@ は 日本語キーボードではPの一つ右、濁点「゛」の位置にありますが、@ が Shi
ft+2 に配置されているキーボードも多々あります。)

☆ ☆ ☆

> // -------- HexDump.dll --------
> // Visual Studio 2019 にて C17 としてビルド。

完成品ありがとうございます。
少しだけ手直しすれば、古いCコンパイラでもすんなり通りそうですね。
私のほうでも実際に試してみようと思います。

> // メモリリーク防止のため、マクロ上で freedll する前に
> Clear() 関数を実行する必要があります。

これは実は、便利な方法があります。
関数名を Clear() から DllDetachFunc_After_Hm866() に変更してください。
そうすれば freedll の直前に自動的に呼んでくれます。

(以前に vscode-life さんの要望で実装された機能です。マクロヘルプの「DLL呼び
出し機能→setdlldetachfunc文」を参照してください。)

[ ]
RE:39812 正規表現DLLに検索文字列などとNo.39814
秀まるお2 さん 22/05/27 14:28
 
 正直、こういう泥沼的な話になるのがいやなのでコメントは一切しないでおきたい
所なんですが、いろいろ歴史的経緯があって、問題が残っているケースもあります。

 他のユーザー様からもいろいろコメントいただいてますが、正しいコメントかどう
かよく分かりません。(僕もよく分かりません)

 \x1Aの制御文字自体ですが、昔々の秀丸エディタではこの文字がテキストデータに
入ってくることはありませんでした。なのであえて4バイトユニコードの先頭文字は
\x1Aを使いました。ところが後になってEOF制御文字も使えるようにしました。しか
し、EOF制御文字は基本的にはファイルの末尾にあるだけで、害はありませんでした。

 ところが・・・、\x1Aをファイルの途中に入れてもちゃんと動かないといけない、
というような話になって・・・秀丸エディタの途中のバージョンで\x1Aは4バイトユ
ニコード文字に変換するようにしました。

 ところが・・・・、いろいろ内部の処理を調べると、必ずしもすべて4バイトに変
換してるかというと、そうでないケースもありまして・・・、その辺がややこしいで
す。

 元々、HmJre.dllの前のJRE32.DLLを使ってなんとかユニコード文字を含む文字列も
検索できないといけないってことで考えた仕組みなので、その辺、多少の矛盾をかか
えていたりします。

 あんまり突っ込まれるとボロが出る可能性ありです。

 あとは・・・・、ソースコード公開したらそれを見て考えてください。繰り返しに
なりますがノーサポートです。

 ノーサポート
 ノーサポート
 ノーサポート

 大事なので3回書きました。

[ ]