ふらっと C#,C♯,C#(初心者用) Part146

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん (ワッチョイ 9f0b-Fgt1)
垢版 |
2019/12/11(水) 22:12:11.28ID:d09CciDz0
!extend:checked:vvvvv:1000:512
次スレを立てる時は↑を2行冒頭に書くこと(1行分は消えて表示されない為)

「どんなにくだらないC#プログラミングやVisual C#の使い方に関する質問でも誰かが優しくレスをしてくれるスレッド」です。
他のスレッドでは書き込めないような低レベルな質問、質問者自身なんだか意味がよく分からない質問、
ググろうにもキーワードが分からないなど、勇気をもって書き込んでください。
内容に応じて他スレ・他板へ行くことを勧められることがあります。ご了承下さい。
なお、テンプレが読めない回答者、議論をしたいだけの人は邪魔なので後述のC#相談室に移動して下さい。
C#に関係の無い話題や荒らしの相手や罵倒レスや酔っぱらいレスはやめてください
>>980を踏んだ人は新スレを建てて下さい。>>980が無理な場合、話し合って新スレを建てる人を決めて下さい。

■前スレ
ふらっと C#,C♯,C#(初心者用) Part145
https://mevius.5ch.net/test/read.cgi/tech/1570446977/
■関連スレ
C#, C♯, C#相談室 Part95
https://mevius.5ch.net/test/read.cgi/tech/1508168482/
■コードを貼る場合は↓を使いましょう。
http://ideone.com/
https://dotnetfiddle.net/

■情報源
https://docs.microsoft.com/ja-jp/dotnet/standard/class-libraries
https://docs.microsoft.com/ja-jp/dotnet/csharp/language-reference/index
https://docs.microsoft.com/en-us/dotnet/standard/class-libraries
http://referencesource.microsoft.com/
・Insider.NET > .NET TIPS - @IT
https://www.atmarkit.co.jp/ait/subtop/features/dotnet/dotnettips_index.html
・DOBON.NET .NET Tips
https://dobon.net/vb/dotnet/index.html
VIPQ2_EXTDAT: checked:vvvvv:1000:512:: EXT was configured
2デフォルトの名無しさん (ワッチョイ 1524-Fgt1)
垢版 |
2019/12/11(水) 22:32:15.34ID:mMKqVbip0
C#
3デフォルトの名無しさん (ワイーワ2 FFfa-uKDx)
垢版 |
2019/12/12(木) 09:41:18.58ID:a67Hqgb2F
O2
4デフォルトの名無しさん (ワッチョイ 06b0-DoXq)
垢版 |
2019/12/12(木) 14:29:42.64ID:56xY8w560
ひらがな文字列をヘボン式ローマ字に変換するプログラム作りたいのですが
やっぱ正攻法でswitch-caseで123個くらい分岐させますか?
でも長音や促音の例外処理とか難しそうだなあ・・・
5デフォルトの名無しさん (エムゾネ FF02-uKDx)
垢版 |
2019/12/12(木) 14:47:29.26ID:b3wcvAqBF
変換テーブルと検索
2019/12/12(木) 17:38:52.89ID:OYDho7HG0
UNIXのShellのソースでコマンドを切り分ける場所では思いっきりswitch文の嵐だったな
1文字目でまず切り分けで、次にに文字目ってな具合で

速度なら圧倒的にswitch分だと思うが、作りやすかったり保守が簡単なのはDictionary使ったパターンだと思う
2019/12/12(木) 17:42:49.22ID:NIaj3T140
要素数が多くなれば多くなる程switch文よりDictionaryの方が速度的にも早くなるのでは?
2019/12/12(木) 17:52:34.02ID:VQC2yHD50
つ libstree
2019/12/12(木) 18:32:36.61ID:Ijd1d2r8M
>>7
C#コンパイラは多数の分岐先を持つswitchの場合には二分探索を行うコードを生成したりする
基本的に人間が最適化するより速い
10デフォルトの名無しさん (ワッチョイ 06b0-DoXq)
垢版 |
2019/12/12(木) 19:09:09.93ID:56xY8w560
>>4です
ありがとうございます
switchでコツウコツやることにします
要素の数え漏れでもっと増えそうだし
例外を拾う処理も考えなきゃww
2019/12/12(木) 19:47:35.25ID:XSG0K+ND0
vs2017ExpressでC#のフォームを使ってSQLiteのデータをDataGridViewに表示させたいです
セキュリティの関係でSystem.data.SQLiteを使うには申請が必要でMicrosoft.data.SQLiteを使っています
SQLiteをデータソース欄に追加する方法を教えてもらえないでしょうか?
2019/12/12(木) 21:16:54.09ID:XSG0K+ND0
ソース貼り忘れました
https://dotnetfiddle.net/DXwCTe
よろしくお願いします
13デフォルトの名無しさん (アウウィフ FF3b-EbeN)
垢版 |
2019/12/13(金) 10:16:06.63ID:V90d9jYdF
いくら払えますか
2019/12/13(金) 11:41:55.37ID:D/hLKfPDd
>>13
自宅でSystem.data.SQLiteをインストールして同じコードを書いたらデータベースに接続出来ました
恐らくSQLiteConnection等の参照が足りずにエラーなっていると思いますが、解決策が思い浮かばなかったのでSQL Serverを使って試したいと思います
申し訳ありません
15デフォルトの名無しさん (スフッ Sd02-cBt2)
垢版 |
2019/12/13(金) 12:10:09.33ID:SSw9bcJtd
Microsoft Visual Studio International Feature Pack を使うんだ!
KanaConversion クラスだったかに RomajiToHiragana メソッドがあったと思う
16デフォルトの名無しさん (ブーイモ MM13-RobM)
垢版 |
2019/12/13(金) 17:23:20.97ID:f86+e1mZM
>>10

亀レスで申し訳ないが、正規表現と Dictionary と LINQ を使えば 5 行くらいで書けるよ。

var kana = “あ|い|う|え|お|か|き|く|け|こ”;
var roman = “A|I|U|E|O|Ka|Ki|Ku|Ke|Ko”;
var dic = kana.Split(‘|’).Zip(roman.Split(‘|’), (l, r) => new { Key = l, Value = r}).ToDictionary( x => x.Key, x => x.Value );

Console.WriteLine(Regex.Replace(original_string, $”({kana})”, match => dic[match.Value]));
17デフォルトの名無しさん (ブーイモ MM13-RobM)
垢版 |
2019/12/13(金) 17:33:03.63ID:f86+e1mZM
あとは 50 音を全パターン書いてね。

ただし注意点があって、長いワードは短いワードよりも (例えば「ちょ」は「ち」よりも) 先に並べるんだ。
そうしないと短いワードが先に部分マッチしてしまう。
2019/12/13(金) 17:47:39.93ID:s9cNxHbdd
テーブル作る前提なら始めからdictionary作ればよくね?
2019/12/13(金) 17:49:41.61ID:s9cNxHbdd
一文字ずつ正規表現でマッチしてたらとんでもなく時間食いそうだな
姓名の変換くらいならどうとでもなるだろうけど
20デフォルトの名無しさん (ブーイモ MMdb-RobM)
垢版 |
2019/12/13(金) 18:16:48.88ID:RrhzxBUdM
>>18
作っているのはテーブルだけではないし、このように書くとスッキリ書ける。

>>19
処理の重さの本質はワード比較による分岐であって、switch 分岐もそれに引きずられるから、C# で比較するならどちらも大差ないと思う。

正規表現の方が、むしろ、最適化がかかることに期待できる。
2019/12/13(金) 18:33:49.64ID:KAf60mjk0
まったくスッキリしてない
圧倒的にswitchが早い
22デフォルトの名無しさん (ブーイモ MMdb-RobM)
垢版 |
2019/12/13(金) 18:44:01.44ID:8Ub64SZCM
>21
それは感情論だな。計時してみてくれよ。

Perl, JavaScript, Java, C# で正規表現を使うこと 30 年弱になるけど、パターンの複雑さによらず、正規表現が目に見えて遅いということはなかったな。

アセンブラでゴリゴリに最適化したものと比べたら遅いだろうが、同じ言語のユーザー定義関数より目に見えて遅いことはまあないと思うよ。
2019/12/13(金) 18:48:06.09ID:04gYwNVod
これならDictionary作るわ
24デフォルトの名無しさん (ブーイモ MMdb-RobM)
垢版 |
2019/12/13(金) 18:51:56.74ID:8Ub64SZCM
>>23
何か勘違いしてないか?
こっちも Dictionary つくっているが。
2019/12/13(金) 19:49:57.23ID:KAf60mjk0
2文字置換を考慮したらスッキリは書けなかった
すまんこ
こんなクソみたいなコードでもregexよりは数倍早い
https://ideone.com/c7ILX4
頭良い人がもっとスッキリしたコード書いてくれそう

長文のほうがreplaceは不利だろうから数千文字にしたけどそれでも余裕
速度気にしないならregexで良いと思う
2019/12/13(金) 19:58:53.60ID:KAf60mjk0
最終文字が2文字置換対象じゃないときにsubstringで範囲外例外出るわ
条件1個追加しといて
2019/12/13(金) 20:57:05.81ID:9t702OJgd
小さい「っ」が未対応なことに気付いた
これ正規表現でもめんどいね
正規表現ならっを無視してreplaceした後に1個ずつ置換かなぁ
28デフォルトの名無しさん (ワッチョイ e752-RobM)
垢版 |
2019/12/13(金) 21:07:14.03ID:M1n71JyZ0
多少簡略化したロジックで計測してみた。

マッチ文字列が 1 文字固定なら、ユーザー定義関数の方が正規表現より 8 倍速かったが、1 〜 2 文字可変なら所要時間は同じ。

パターンマッチの文字列長が可変・複雑になるとそれをハンドルするための分岐が増えるせいでユーザー定義関数は遅くなる。

もちろん置換をかけるオリジナル文字列の文字出現パターン&確率にもよる。

チューニングするなら C やアセンブラで書くべきだし、C# で書くなら正規表現で簡潔に書けるほうがよいのでは?
29デフォルトの名無しさん (ワッチョイ e752-RobM)
垢版 |
2019/12/13(金) 21:12:22.88ID:M1n71JyZ0
>>27
おもしろいところに気づいたね。

例えば仮文字 $ とかに変換しておいて、最後に直後の子音字に変換。

ちゃっと => cha $ to => cha t to
2019/12/13(金) 21:22:02.14ID:VulPdUq80
どうあがいてもregexは遅くないという結論にしたいみたいだけど
string単体で見ても遅いのにregexが遅くないわけがない
簡潔に書くならregexがスマートなパターンが多いのは分かってるよw
処理速度求められるパーサーなんかではまずregexなんか使わない

遅いと言っても数万文字の処理が何万回も必要とかでなければ気にするようなレベルではないので問題ないなら素直にregex使ったほうが良いよ
25ですでにそう言ってるしね
31デフォルトの名無しさん (ワッチョイ e752-RobM)
垢版 |
2019/12/13(金) 21:26:23.93ID:M1n71JyZ0
あるいはワンショットで置換するなら、下記のようなパターンを使って後方参照し、第1マッチ文字列が空でないなら、第2マッチ文字列の置換先の1文字目に置換するとか。

(っ?)(あ|い|う|え|お|か|き|く|け|こ)
2019/12/13(金) 21:26:56.26ID:yXJ+I/RUa
「ンョ゛ハー ゛」みたいなのが来た時の対応とか考え出すと仕様肥大化するだろうなあ
ひらがなカタカナ両対応とか、半角カナとか、
長音の代わりにハイフン使いだした場合とか
「ヴァッソ」とか
テストパターン考えるのも厄介そうだね
33デフォルトの名無しさん (ワッチョイ 5f01-uKDx)
垢版 |
2019/12/13(金) 21:30:11.16ID:0IHjBlJG0
LALRを受理するジェネレータ書いたことがあるんだけど、状態表の大きさは字句解析のほうが遥かに大きくなるのが普通みたいですよ。
字句解析と構文解析は一つの表にまとめられるのに、なぜ分けるのかというのが最初の疑問だけど、なぜか答えが載ってる本が無い。
実際にやってみると表の大きさが爆発的に大きくなるからでした。
状態機械は分けられる箇所があるなら積極的に分けたほうが効率的になるようです。
34デフォルトの名無しさん (ワッチョイ e752-RobM)
垢版 |
2019/12/13(金) 21:30:12.87ID:M1n71JyZ0
>>30
文字列操作だからもちろん絶対的には遅いよ。

C# で書いたユーザー定義関数と比べたときに正規表現が相対的にそんなに不利かといったらそうではないだろうという予想を立てただけで。実際測ったら同等だったわけだけど。
2019/12/13(金) 21:30:26.83ID:7oWhly6q0
日経だったか「むかっっ」という促音が
重なる文章というか記事があったな
36デフォルトの名無しさん (ワッチョイ 5f01-uKDx)
垢版 |
2019/12/13(金) 21:33:36.65ID:0IHjBlJG0
字句解析におけるNFA対DFAというのも最初に気になる部分です。
結論から言うと、NFAの選択は十分に考慮できるはずです。
僕も最初はDFAにこだわっていました。
でも、字句解析は表が大きくなりがちです。
特にregex並みの便利機能を組み込もうとすると、とても大きくなります。
たいていはNFAで十分かと思います。
37デフォルトの名無しさん (ワッチョイ 5f01-uKDx)
垢版 |
2019/12/13(金) 21:37:02.69ID:0IHjBlJG0
ちなみに、DFAにこだわる理由は、多くの本がDFAのほうが効率的と述べているからです。
みんなそうだと思います。
最悪のケースではその通りですし、最悪のケースを考慮するのはセキュリティにも関わります。
でも最悪のケースはめったになく、たいていはNFAで十分で、たいていは効率的だと思います。
2019/12/13(金) 21:39:05.74ID:VulPdUq80
>>34
その同等だったっていうコード貼ってくれない?
25で貼ったコードで1文字2文字の比率変えてもregex側が常に3〜4倍くらい遅いんだよね
古い.NETだとsubstringが遅いとかあった気がするんだけどその影響じゃないよね?
39デフォルトの名無しさん (ワッチョイ e752-RobM)
垢版 |
2019/12/13(金) 21:42:16.88ID:M1n71JyZ0
>>38
コード書いてくれてたんだね。
25 があぼーんで読めない。。。
40デフォルトの名無しさん (ワッチョイ 62b0-DoXq)
垢版 |
2019/12/13(金) 21:42:32.85ID:f+S2ArPq0
>>4でーす
>>16以降、何書いてるのかサッパリ分かりません!
なんせまだifとforとswitchと文字列操作のメソッドくらいしか知らないもんでww
半年くらい後に読みに来まーす
41デフォルトの名無しさん (ワッチョイ e752-RobM)
垢版 |
2019/12/13(金) 21:51:25.19ID:M1n71JyZ0
>>38
コードは長すぎて多分アップできないと思う。

やっていることは switch 式を2 文字マッチの場合と 1 文字マッチの場合で 2 種類つくり、残文字列が 2 文字以上あるなら前者にかける (破棄パターン _ => で後者を呼び出す)、1文字なら後者にかけ、インデックスを進めるだけ。

置換後文字列の連結には StringBuilder 使っているし、メソッド呼び出しは AggressiveInlining している。ユーザー定義関数を意図的に遅くするようなことはしていない。

1文字あるいは2文字の切り出しに Substring 使っているけど、それが遅いのかな?
2019/12/13(金) 21:52:27.04ID:yXJ+I/RUa
ローマ字変換でばっとググってみた

お勉強用ならJavaScriptで書かれてるこれを理解しながらC#に移植するのがよさそうかな
ソースコードも簡潔だし悪くなさそう
https://www.pandanoir.info/entry/2016/03/29/190000

とにかく動けばいいというならMicrosoftが配ってるらしい「Japanese Kana Conversion Library」?でもこんなの使ったことないや
2019/12/13(金) 22:00:14.44ID:+9OE4qBy0
ンボマはmboma
ンバッペはmbappe
だからね

練習用なんだろうけど
簡単に見えても文字変換を自力でやるのはかなり面倒くさい
2019/12/13(金) 22:10:51.66ID:+9OE4qBy0
正規表現のほうが単純文字列比較より遅いのは当たり前
1文字比較の場合に単純比較と同等になるような
最適化が施されてるエンジン積んでれば数倍とかの差はつかない

少し古いバージョンのブラウザのJSのなら平気で10倍近い差が出てた
でもその差がUXに影響を与えるようなユースケースはそう多くはない

ちなみにstringのswitch caseは数が増えると
.NET Core以前は内部的にDictionary使うみたいよ
.NET Coreもhash比較するのは同じだけどDictionaryをアロケートしない方法にしてるらしい
2019/12/13(金) 22:12:49.12ID:VulPdUq80
>>39
これで見えるかね
ttps://ideone.com/c7ILX4
このコードはswitchじゃなくDictionaryでやった
おそらくswitchのほうがこれより早くなるか最適化で同程度になるはず
switch版までは作るのめんどい

配列の境界値チェックも遅い要因なのでできるだけチェックが発生しないのが望ましい
このコードでは2文字変換したときに境界値チェックが入ってしまうので2文字変換比率が高いと性能が悪くなる
2文字変換ばかりにしてもregexよりは早い
46デフォルトの名無しさん (ワッチョイ e752-RobM)
垢版 |
2019/12/13(金) 22:38:36.62ID:M1n71JyZ0
>>45
ありがとう。週末に評価してみる。

switch より Dictionary の方が処理性能がぶれない気がする。ハッシュで検索がワンショットに決まるから。switch は if カスケードを通ることで前スレで議論したパイプライン処理の影響を受けるため、処理速度がデータに強く依存する。

そんなわけでこの件の性能はコードの書き方 (チューニング含む)、データ、環境にかなり依存すると思う。

これは価値観の問題なのでみなが同じように考えるとは思わないが、正規表現で 3 - 4 倍程度の性能悪化なら、ユーザー定義関数よりチューニングより正規表現を私は採用する。
10 倍の悪化なら用途によっては考える。(パターンが複雑・多岐の場合) 正規表現は開発効率と保守性が 10 倍よいと思うので。
2019/12/13(金) 22:59:26.50ID:x4Cvv/aS0
>>46
switchとdicの関連は44が説明してくれてる
最適化次第でいい感じにしてくれるはずだからどっちもたいさない感じになると思う

個人的には性能差が10倍だろうが1000倍だろうが許容できるケースなら可読性を取る
今どき文字→数値変換でc-'0'なんて書かずに大体int.Parse使うのと同じ

UIに入力された氏名のローマ字変換みたいな1ユーザー1回で済むような処理に速度なんて無意味
GB単位のログデータをいじるなら数倍の差でも考慮すべき
なんなら入力データの傾向に応じてチューニングしやすい単純処理のほうが更に高性能にしやすい
2019/12/13(金) 23:21:38.26ID:Lnvxq+5t0
俺なら、ひらがな小文字の変換は、変換元「ちゃ」とか「ぱっ」のパターンを文字数降順で優先的に置き換えるかな。
配列で変換パターンを保持して、それにない文字パターンは先頭から徐々に削っていく。
それなら「ぱ」と「は゜」なんかも判りやすく対応できると思うよ。
49デフォルトの名無しさん (ワッチョイ e752-RobM)
垢版 |
2019/12/13(金) 23:36:31.48ID:M1n71JyZ0
>>44, 45, 47
みんな有益な考察をしてくれるのでありがたい。感謝。

今まで正規表現が際立って遅いと体感することなかったけど、利用目的を想定した評価をきちんとしたことなかったので一連の議論はとても参考になりました。
2019/12/13(金) 23:57:37.29ID:+9OE4qBy0
オリジナルの文字列を1文字ずらしでzipして
2文字ずつ取得するイテレータでやるのがいいかなとか思ってたが
多少非効率でも↓ここの実装みたいに繰り返し変換していく方が
条件分岐が少なくて読みやすいかも

https://tools.m-bsys.com/original_tooles/romaji.php
https://tools.m-bsys.com/js/romaji.js

function hebonG(s) {
s = s.replace(/ん([aiueoy])/g, "n$1");
s = s.replace(/ん/g, "n");
s = s.replace(/n([bpm])/g, "m$1");

var hebonGMap = {
"kuぁ": "kua", "kuぃ": "kui", "kuぇ": "kue", "kuぉ": "kuo",

}

s = s.replace(/っch/g, "tch");
s = s.replace(/っ([kstnhmyrwgzdbp])/g, "$1$1");
2019/12/14(土) 11:11:39.02ID:8NRAnTxB0
>>49
正規表現が遅いのは、コンパイルだろ

実行時ではなく、初期化時にコンパイルするようにと、Go の本には書いてある
2019/12/14(土) 11:24:37.56ID:8NRAnTxB0
>>4
Ruby では、条件分岐しなくても、変換用の辞書で書ける

>>16
も、これに似ている

hash = { 'ab' => 'あ', 'xy' => 'ん' }

p re = Regexp.union( hash.keys ) #=> /ab|xy/

p "9xy9ab9xyx".gsub( re, hash )
#=> 9ん9あ9んx
53デフォルトの名無しさん (ワッチョイ e752-RobM)
垢版 |
2019/12/14(土) 16:02:25.78ID:BZ704rid0
>>51
まあね。ただ、C# の Match Evaluator 付き Regex.Replace は事前コンパイルできないと思う。

ちなみにあの後何度か測り直したのだが、switch より事前コンパイルなし正規表現は 2 倍遅かった。同等ではなかった、すまん。

45 によると Dictionary & ユーザー定義文字列操作は正規表現より 3-4 倍良かったそうだから、今回のケースでは Dictionary : switch : 事前コンパイルなし正規表現 = 3-4 : 2 : 1 くらいの性能比かと考えられる。

switch はカスケードがさらに増えると内部で Dictionary 化して最適化されるから、一般論としては 正規表現は事前コンパイルすれば switch に肉薄する、あるいは、多少超えるかもしれないが switch に Dictionary 最適化がかかったらまた離されるかもって感じではないかと。

>>52
ありがとう。Match Evaluator 正規表現でハッシュ置換するのはもう四半世紀も使っているテクだけど他で見たことなかったから、Ruby の例は参考になる。
2019/12/15(日) 00:27:58.57ID:x+hGNtUDa
このスレにいる人たちで
C#を日本語で記述ってのを実際にやってる人、どれくらいいるかな
https://togetter.com/li/1441951 を読んで試してみてもいいかなと思ったんだけど
VisualStudioのコード補完が利く環境ならIME切替の手間もさほどかからない気もするし
何か致命的なデメリットとかあるんだろうか
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況