はてなキーワード: stringとは
割りとマジだよねと思う出来事をふと思い出したので書いてみる。
といっても後輩が俺の思ってもいないところでつまづいて、それに俺がカルチャーショックを受けたというだけの話。
問題の話なんだけど、とある有名サービスのJSON APIを叩いて呼び出し結果を手元のオブジェクトにマッピングするというただそれだけのコードを書くというもの。
普通に考えて一日もしないで出来ると思うような代物だけど、三日以上悩んで彼はそれでも出来なかった。
{ ..., "count": 10000000000000000000000000000000000000, ...}
という感じで多倍長整数がリテラルとして書かれているのを前提として受け取る仕様だった。
JavaScriptの通常の整数と違って、JSONの整数リテラルは仕様上大きさの制限の記載がないので、上のようなのも合法。
で、彼の使ってたプログラミング言語のオブジェクト から JSONの変換ライブラリが、多倍長整数を文字列("")としてシリアライズするような仕様なことがわかって、彼は行き詰まった。
そこで何をやり始めたかというと、JSONの整数がそのまま1000000000000000みたいにシリアライズされるライブラリ探し始めたんだけど、それは見つからないまま。
というわけで「増田さん、詰まってるんですけど……」と言われて助け舟出すことになったはいいものの、彼のコード見るとJSONの抽象構文木クラスがそのまま使えるようだった。
なので、
String serialiaze(Ast.JsValue value) { return switch(value) { case Ast.JsNull nullValue-> "null"; case Ast.JsInt bigIntValue -> bigIntValue.toString(); case Ast.JsArray arrayValue -> arrayValue.stream().map(v -> serialize(v)).collect(Collectors.joining(", ", "[", "]")); // 他のJSONの木についても同様に処理 default -> throw new RuntimeException("cannot reach") }; }
1時間しない内にこんな感じのコード(言語はJavaじゃなかったけど、だいたいこういう感じ)を書いて無事問題解決。細かいタイポとかあるかもだけど、日記では確認してないのでそれはおいといて)。
結局、JSONの形が期待と違って、しかも既存のAPIじゃいいのがなかったのに延々API探すことしか出来なかったのが問題解決できなかった原因だけど、このくらいのは割りとちょこちょこある。
きっと、それから一週間放置しても問題解決できなかっただろうし、どうも同じチームの同僚も問題を解決できなかったようだった。
最近、APIは叩けるけど、そこでトラブルとどうにもならなくエンジニアにちょくちょく遭遇するんだけど、やっぱりもうちょっと基礎出来てないと駄目だなと思った出来事だった。
自分は上段に座しているつもりで偉そうな上から目線の半分的外れな説教だの、はたまたその体すら為していない放言だのを安全な位置から投げつけたいだけのカスしかここにはいない。
このタイトルを見て、意識高い系文系イキリ勘違い野郎に何事か物申してやろうと考えたそこの画面の前でニチャニチャしているパソカタオタク(パソコンカタカタキモオタク: 声は小さいがタイプ音はでかい)のことである。
あるいは増田のことかもしれない。増田は日頃増田に生息している訳ではないが。
お分かりの通り、これは釣り記事である。そもそも意識高い系文系イキリ勘違い野郎が増田に記事を書くわけがない。が、一応タイトルに嘘はない。
ので意識高い系文系イキリ勘違い野郎を志す意識高い系文系イキリ勘違い野郎予備軍のことを思って以下を書く。
ちなみに、この記事のタイトルは増田が一番嫌いなタイプのそれである。自分で設定したのに今、額に青筋が浮かんでいる。
本項ではWebエンジニアになるにあたって増田がやったことを列挙する。
1. プログラミングを独学する
2. スクールに入る
3. アルバイトをする
なるほど、至極単純である。では順に詳細を見ていく。
ここに関しては特に言うこともない。
ネットの記事を見ながらCだのDだのC++だのを実際に吐くまで勉強した。
その経験を踏まえて意識高い系文系イキリ勘違い野郎予備軍にアドバイスするならば、独学の上で最も身になるのは"C++を用いて簡単なスクリプト言語のインタプリタを実装する"ことである。
インタプリタの実装という作業はプログラミング言語そのものに対する解像度を飛躍的に向上させる。
不可思議なお約束の塊であった文法や意味論が因数分解されるように頭の中で整理され、ブラックボックスであった標準ライブラリの内部について想像が及ぶようになる。
道具たるプログラミング言語に対する理解は、当然その使途であるプログラミングそのものを助ける。
ところでパソカタオタク諸兄姉は「なぜ今C++などという時代遅れのクソ言語を」と思ったかもしれない。
確かにC++はもはや洗練から程遠い聳えるバベルの塔である。しかし、こと言語実装の習得においてはこれほど適している言語もない。
C++はGC付きの他言語と比較して抽象度が低く、全てを自身で管理しなければならないが故に"便利な魔法"にあまり頼れないのである。
また、C++で導入された様々な思想、イディオムは他の言語にも大きく引き継がれている。
例えば洗練という意味でC++の対極に位置するRustという言語は、もはや本質的にはC++そのものである。
Rustの代名詞である所有権、ライフタイムはそれぞれC++の反省から生まれた言語要素であるし、move semanticsはC++11におけるmove semanticsと同様のものである。
GC付き言語の利用者にとってしばしば混乱の原因となりそうな`str`と`String`も`std::string_view`と`std::string`を知ってさえいれば迷いの発生する余地はない。
他のより抽象化された言語についても、C++との対応を考えることでその言語や標準ライブラリそのものの実装について十分に理解を深めることができる。
なぜならば過去の多くのスクリプト言語やコンパイラはC/C++によって実装されていることが多いからである。
そんなわけで、増田は"C++を用いて簡単なスクリプト言語のインタプリタを実装する"ことを勧めている。
増田が入ったスクールは、多くのそれが半年あたり70万程度の授業料を取る(らしい)のに対して同期間で28万程度と非常にリーズナブルであった。
ただし、卒業までは最低4年と長期間を要するし、増田は卒業後も2年さらに通った。
おいそこの意識高い系文系イキリ勘違い野郎予備軍、カスみたいなプログラミングスクールに入るな。
ところでそろそろ察せられるだろうが、増田の前職とは学生を指している。
大学は情報工学を教えてくれるが、別段それを学んだからといってプログラミングができるようになるわけではない。あくまでそれらは相補的なものである。
一方で、独学では分野に偏りが出がちだし、なにより独学にも金が要るので学生の身分にとってプログラマのバイトは良い選択肢である。
アルバイトはITエンジニアの経験に含めなくて良いのか怪しいが、増田のバイトの業務内容はWebエンジニアと言いきってよいか悩ましい類だったので嘘は吐いていない。
ちなみに増田は増田に書き込むような人間であるからして社会性というものが欠落している。
ちなみに月収は大学院2回生の収入0時代からの差分で算出して+50万なのでつまるところそれが現在の月収である。
増田にとって低くはないが、決してITエンジニアとして高い方であると主張することはできない程度の額である。
釣りのためにタイトルに含めた以上最低限の説明のはしたが、増田は金の話をすると脳の血管がブチギレそうになるのでこれ以上その話はしない。
ここまで読んだならわかると思うが、増田は意識高い系文系イキリ勘違い野郎(タイプ音がでかい)ではなく、パソカタオタク(パソコンカタカタキモオタク: 声は小さいがタイプ音はでかい)である。
そして、意識高い系文系イキリ勘違い野郎予備軍に言うべきことがあるとすれば、そもそもこの記事をここまで読んでいる時点でITエンジニアには向いていないので止めといたほうがよい。
また、ひょっとすると思い違いをしているかもしれないが、ITエンジニアというのは大抵 (増田は社会経験がほぼないので一般論を言うことは出来ないが) 意識高い系イキリキラキラ野郎サイドではなくパソカタオタクばかりである。
というよりTwitterにいる意識高い系イキリキラキラ野郎は多くの場合意識高い系文系イキリ勘違い野郎予備軍を養分にする人でなしである。騙されてはならない。
また、一つ理解しなければならないのは意識高い系文系イキリ勘違い野郎予備軍諸兄姉が張り合わなければならないのは、プログラミングスクールの同期でも、「#駆け出しエンジニアと繋がりたい」している有象無象でもなく、幼少から寝食や友人や遊びを自ら捨ててパソカタにのめり込んでいた、そして現在進行系でのめり込んでいる歴10年や20年をゆうに超えるSSRパソカタオタクであるということである (そしてそれはNRパソカタ増田も同様である)。
彼らが「スクールで半年学びました」で並び立てるような人間でないのは単純な算数でわかるほど明らかである。悪いこと言わんからキラキラWebエンジニアを目指すのはやめとけ。
あるいはそれでも目指すのであれば自分が何を捧げられるのかを考えた方がいい。
自動で安価をつけて返信するプログラムでもこんなに長く複雑になる(一部抜粋)
/**************************************
以下のCSV_DIR, FILE_PATHS, SETTINGSを書き換えてね。 <h3>o- *************************************/</h3>
//CSVファイルが置かれてるディレクトリのパス。投稿前にエラー出たら大体ここの設定ミス。 例:"C:\\Users\\sakuraimasahiro\\Documents\\iMacros\\Macros\\rentou\\";
'C:\\Users\\USER\\Desktop\\iMacros\\Macros\\rentou\\';
//ファイルのパス。CSVは絶対パスで、拡張子も必要。iimは相対パスでよく、拡張子不要。
const FILE_PATHS = {
textCsv: CSV_DIR + 'textNoAnker.csv',
//レス用投稿文が書かれたCSV。通常とレス用で分けないなら同じファイルを使えばいい。
replyTextCsv: CSV_DIR + 'textReply.csv',
};
baseWaitTime: 5,
//baseWaitTime+0~waitTimeRange(ランダム)だけ待つ
waitTimeRange: 5,
//連投しすぎだと忠告された場合に処理を一時停止させる時間(秒)
waitTimeForAvoidingPunishment: 60 * 30,
//メール
mail: 'sage',
//名前設定
name: '',
//以下、偽装ワッチョイ設定。浪人でワッチョイを非表示にしてるときだけtrueにしてね。
//妙なニックネーム(ワッチョイ、アウアウウーなど)をランダムで決めて付加するかどうか。true=付加する。false=付加しない。
//妙なニックネームの後に付く8桁の文字列をランダムで決めて付加するかどうか。
},
//アンカー無し投稿をするならtrue。しないならfalse。noAnkerPostかreplyPostのどちらかはtrueにすること(両方trueでもOK)。
//アンカー付き投稿(返信)をするならtrue。しないならfalse。もしnoAnkerPostとreplyPostの両方がtrueの場合、投稿は返信が優先され、返信対象が見つからなくなったらアンカー無し投稿をする。
//最初に取得するアンカー無し投稿文CSVファイルの行番号。もし返信用と同じCSVファイルを使うなら-1と入力。
noAnkerPostTextCsvStartRow: 1,
//最初に取得する返信用投稿文CSVファイルの行番号。もしアンカー無しと同じCSVファイルを使うなら-1と入力。
//テキストCSV/返信用テキストCSVの取得行が最終行に達したら最初の行まで戻るかどうか。true=戻る。false=マクロ終了。
//返信する場合、これより小さなレス番には返信しない。返信を投稿すると、この数値は前回の返信先のレス番に更新される。
minAnker: 895,
//返信する場合、名前に以下の文字列を含む投稿にアンカーをつけて返信する(ワッチョイやIPなど名前フィールドにあるものならなんでも可)。配列で複数指定可能。指定無しなら空配列([])。filterNamesとfilterNamesNotIncluded共に無指定ならレス番1から順に返信していく(minAnkerが設定されてればそこから順に)。以下のfilter系は全て併用可能。
//↑とは逆に、名前に以下の文字列を含まない投稿にアンカーをつけて返信する。↑と併用も可能。
//返信する場合、本文に以下の文字列を含む投稿にアンカーをつけて返信する。
filterText: ['自演かな', '自演わらわら', 'スクリプト使うの', '安価ガバ', '>>660', '自演で擁護', '最後' ,'あいうえお', 'かきくけこ', 'さしすせそ', 'なにぬねの', 'はひふへほ', 'まみむめも', 'やいゆえよ', 'やゆよ', 'らりるれろ', 'わいうえを', 'わをん', 'わいうえをん'],
},
//自分のIPアドレスの確認。VPNとかでIPを変更してマクロを動かしてるとき、突然VPNが作動しなくなってIPが元に戻ったときにマクロを止めるためのもの。
//以下の文字列が自分の現在のIPアドレスに含まれている場合、マクロを一時停止する。基本的に自分の本当のIPアドレスを入力。
},
//浪人設定。最後に動作を確認したのは5年くらい前で、今も同じように動作するかは、浪人を持ってないから確認できずわからない。
//浪人にログインしてるかどうかをチェックするかどうか。trueならする。falseならしない。trueにしていてもし浪人にログインしていないことを確認したらログインしにいく。
password: '1234',
},
};
/**************************************
設定箇所終わり。
https://info.5ch.net/index.php/%E6%9B%B8%E3%81%8D%E8%BE%BC%E3%82%81%E3%81%AA%E3%81%84%E6%99%82%E3%81%AE%E6%97%A9%E8%A6%8B%E8%A1%A8 <h3>o- *************************************/</h3>
/**************************************
・NULL演算子(??)は使えない。論理積(&&)は使える。
・オブジェクトの分割代入はできない。
・importはできない。 <h3>o- *************************************/</h3>
/**************************************
関数 <h3>o- *************************************/</h3>
/**
* ここから始まる。
*/
checkSettings();
var _TextCsvCursors = new TextCsvCursors(
SETTINGS.postSettings.noAnkerPostTextCsvStartRow > 0
? SETTINGS.postSettings.noAnkerPostTextCsvStartRow - 1
: SETTINGS.postSettings.noAnkerPostTextCsvStartRow,
SETTINGS.postSettings.textCsvLoop,
),
SETTINGS.postSettings.replyPostTextCsvStartRow > 0
? SETTINGS.postSettings.replyPostTextCsvStartRow - 1
: SETTINGS.postSettings.replyPostTextCsvStartRow,
SETTINGS.postSettings.textCsvLoop,
),
);
var _LoopStatuses = new LoopStatuses(0, SETTINGS.postSettings.minAnker);
const _MyPosterName = new MyPosterName({
name: SETTINGS.nameSettings.name,
});
const _ThreadUrl = openPromptThreadUrl();
//ループ
while (true) {
SETTINGS.ipSettings.checkIp && checkCurrentIpNotTheIp();
//スレを開く
openUrl(_ThreadUrl.fullUrlHttps());
//浪人にログインする設定なら、浪人にログインしているかどうかを確認し、していなければログインしにいく。
if (SETTINGS.roninSettings.checkLogin) {
}
}
if (SETTINGS.postSettings.replyPost) {
const targetAnkerNumber = createPostDOMList()
.filterPostnumberHigher(_LoopStatuses.currentMinAnker())
.filterByPostername(SETTINGS.postSettings.filterNames)
.filterByPosternameNotIncluded(
SETTINGS.postSettings.filterNamesNotIncluded,
)
.filterByText(SETTINGS.postSettings.filterText)
if (targetAnkerNumber !== null) {
const r = _TextCsvCursors.takeNextRowTextAsReply(targetAnkerNumber);
messageDisplay(`返信対象有り。アンカー先: ${targetAnkerNumber}`);
return {
...r,
updatedLoopStatuses:
_LoopStatuses.updateMinAnker(targetAnkerNumber),
};
}
}
if (SETTINGS.postSettings.noAnkerPost) {
//返信対象無し、或いは返信しない設定の場合。アンカー無し投稿文を作る。
const r = _TextCsvCursors.takeNextRowTextAsNoAnker();
messageDisplay('返信対象無し。アンカー無し投稿。');
return {
...r,
updatedLoopStatuses: _LoopStatuses,
};
}
return null;
})();
if (p) {
//投稿。
nickname: SETTINGS.nameSettings.nickname,
korokoro: SETTINGS.nameSettings.korokoro,
area: SETTINGS.nameSettings.area,
}),
SETTINGS.mail,
p.text,
);
//_TextCsvCursorsと_LoopStatusesを更新。
_TextCsvCursors = p.updatedTextCsvCursors;
_LoopStatuses = p.updatedLoopStatuses.incrementPostCount();
`投稿回数: ${_LoopStatuses.currentPostCount()}`,
`minAnker: ${_LoopStatuses.currentMinAnker()}`,
`今回アンカー無し投稿取得行: ${_TextCsvCursors.currentRows().noAnker}`,
`今回アンカー有り投稿取得行: ${_TextCsvCursors.currentRows().reply}`,
]);
} else {
`返信対象が現われるのを待機中...。`,
`投稿回数: ${_LoopStatuses.currentPostCount()}`,
`minAnker: ${_LoopStatuses.currentMinAnker()}`,
`今回アンカー無し投稿取得行: ${_TextCsvCursors.currentRows().noAnker}`,
`今回アンカー有り投稿取得行: ${_TextCsvCursors.currentRows().reply}`,
]);
}
wait(SETTINGS.baseWaitTime + randomRange(0, SETTINGS.waitTimeRange));
}
}
/**
* 投稿処理と投稿結果を見てリトライしたりマクロ終了したり。
* @param {string} serverName サーバー名
* @param {MyPosterName} _MyPosterName
* @param {string} postMail メール
*/
serverName,
postMail,
_MyText,
retryTimes = 0,
) {
const r =
retryTimes === 0
? new ValuesOfPost(serverName, _MyPosterName, postMail, _MyText).post(
postTo5chTread,
)
serverName,
postMail,
_MyText,
).postSubstring(retryTimes, postTo5chTread, postConfirm);
if (r) {
back();
return;
}
wait(7);
const error = createPostErrorMessage().analyze();
messageDisplay(error.message);
if (error.order === 'KILL') {
kill();
} else if (error.order === 'SKIP') {
return;
} else if (error.order === 'TRUNCATE') {
back();
serverName,
postMail,
_MyText,
retryTimes + 1,
);
} else if (error.order === 'WAIT') {
wait(SETTINGS.waitTimeForAvoidingPunishment);
serverName,
postMail,
_MyText,
retryTimes,
);
} else if (error.order === 'LOGIN') {
serverName,
postMail,
_MyText,
retryTimes,
);
}
return;
}
/**
* 現在のIPアドレスに、SETTINGS.ipSettings.avoidTheIpの値が含まれていないことを確認する。含まれていたらマクロを一時停止。
* @returns
*/
function checkCurrentIpNotTheIp() {
openUrl('https://www.cman.jp/network/support/go_access.cgi');
const _IpAdress = createIpAdressFromCMan();
if (_IpAdress.includes(SETTINGS.ipSettings.avoidTheIp)) {
pause('現在のIPに指定した値が含まれていることを確認。');
}
return;
}
/**
* @returns
*/
if (
SETTINGS.postSettings.noAnkerPost === false &&
SETTINGS.postSettings.replyPost === false
) {
return kill('設定エラー。noAnkerPostとreplyPost両方ともfalseになってる。');
}
if (
SETTINGS.postSettings.noAnkerPostTextCsvStartRow < 0 &&
SETTINGS.postSettings.replyPostTextCsvStartRow < 0
) {
return kill(
'設定エラー。noAnkerPostTextCsvStartRowとreplyPostTextCsvStartRow両方とも-1になってる。',
);
}
if (
SETTINGS.postSettings.noAnkerPostTextCsvStartRow === 0 ||
SETTINGS.postSettings.replyPostTextCsvStartRow === 0
) {
return kill(
'設定エラー。noAnkerPostTextCsvStartRow/replyPostTextCsvStartRowの初期値は-1或いは1以上で。',
);
}
}
/**
* 入力フォームを表示して入力されたスレのURLを受け取る。
*/
function openPromptThreadUrl() {
const url = prompt('スレURLを入力');
}
/**
* 開いてるスレのレス全て読み取ってPostListインスタンスを作って返す。
* 重すぎるので使うのやめ。どうやらインスタンスの大量生成が原因な模様。
*/
const posts = window.document.getElementsByClassName('post');
return new PostList(Array.from(posts).map((e) => new Post(e)));
}
/**
* 開いてるスレのレス全て取得してPostDOMListに格納して返す。
* @returns
*/
function createPostDOMList() {
const posts = window.document.getElementsByClassName('post');
for (let index = 0; index < posts.length; index++) {
//HTMLCollectionからElementを1つずつ抽出して配列に。
arrPostDOMList.push(posts.item(index));
}
return new PostDOMList(arrPostDOMList);
}
/**
* 開いてる投稿結果画面に表示されてるエラーを読み取ってPostErrorMessageインスタンスを作って返す。
*/
function createPostErrorMessage() {
window.document
「google apps script string bracket error」とかでググればええんちゃうの。知らんけど。
装備のセットにあたま、防具、こてみたいな種類があってそれをList<List<bool>>で管理していた
この変数とは別にアイテム一覧みたいな変数もあって(String[]{初級、冒険者、炎。。。}みたいな)そこと突き合わせて使っていた
これはDB管理するときに一つのこの変数自体を一つのKeyValueで管理していたからなんだけど
最近そういうものを管理するための方法が用意されてて、〇〇セットKeyValueで{頭 = true、防具。。。}みたいなセットごとに保存するAPIがあることを知った
だからローカルのほうでもList<Bool>じゃなくてClassとか構造体に変えることも可能なんだけど、これってわかりやすさのために変えるべき?
開発終盤でショップ機能とか装備入れ替えで使ってるから結構修正いるんだが、DBから引っ張てくるときにList<bool>に変えることで対応も可能
プログラマーに憧れる皆さん!こんばんは。
「自分は文系だから」「未経験だから」と諦めていませんか?大丈夫です!プログラミングにセンスは不要です。正しい手順で学べば、文系や未経験でも、誰でも一流のプログラマとして活躍することができます。
今日は、未経験から最短でWeb系企業に就職するための勉強法をご紹介します!
もっともオススメの方法は、顕正会のセミナーに参加することです。
顕正会は、日本で最大のエンジニアのコミュニティであり、非常に良質なテキストを用いて、プログラミング初心者向けのセミナーをしていることで有名です。顕正会に入ることで、未経験からでも一流エンジニアのノウハウを学ぶことができます。
また、意外と知られていませんが、日本のエンジニアの8割は顕正会の出身です。実はあのひろゆきやビル・ゲイツも顕正会の出身です。ですので、顕正会のネットワークを介して就職先を斡旋してくれたりしますし、自分が顕正会員だと、面接時にも非常に有利になります。
顕正会のセミナーは、インターネットからも応募することができますし、秋葉原などで声をかけられることもありますので、誰でも簡単に参加できます。会員もフレンドリーな方ばかりですので、是非、お気軽に応募してみて下さい!無料体験もできますよ。
プログラミングの勉強を始める前に、まず、必要なものを準備しましょう。必ず必要なものと、できればあると良いものは以下の通りです。
可能な限りスペックの高いものを買いましょう。2021年現在であれば、CPUは18コア、36スレッド。RAMは128GBくらいはあると良いでしょう。ストレージはSSDであれば1TBもあれば十分です。
OSは、Windowsで開発するならWindowsが、Macで開発するならMacが必要です。よく分からなければMacを買っておく方が良いでしょう。基本的にMacにできてWindowsにできないことはありません。
インターネットは、この記事を見ている人は既に持っているでしょう。ただし、モバイル回線で見ている人は、自宅に有線のインターネット環境を用意した方が良いです。
顕正会に入会すれば、上記のスペックのPCを無料で貸し出ししてくれます。また、法人向けの専用線を無料で取付工事を行ってくれる上に、通信費を全て負担してくれます。
まず、他の会員と連絡を取るために、SNSのアカウントを持っていると良いでしょう。
最近は完全にPC上での学習もできますが、やはり、勉強の基本は紙のノートに直接書くことです。医学的にも、手指の動きと脳の記憶回路が関連していることは証明されており、手を動かすことで効率的にものを覚えることができます。
Kindleなどの電子書籍リーダーは持っておいた方が良いです。紙の本は時代遅れです。いやしくもITのプロを目指そうという人間が、このような最先端のデバイスを使っていないのは恥だと思うべきです。紙の本を買わないことは、環境を守ることにも繋がります。現金も持つのはやめましょう。
せっかくセミナーに参加しても、受身で聴くだけでは、プログラミングを習得することは難しいです。ここでは、自宅でどのような勉強をすればよいのか、ご紹介します。
まずは、教科書や参考書を写経することから始めましょう。教科書や参考書の本文を一字一句正確に書き写すのです。
よく、「写経は理屈を学べないからだめだ」と批判されますが、まずは正しい「型」を体に覚え込ませるのが先です。野球や水泳などでも、細かい理屈よりも先にフォームを固めるのと同じです。書き写している内に理屈は自然と身に付きます。
また、写経のメリットは「飛ばし読み」を防げるところです。一字一句正確に写経をすれば、細かい部分を「分かったつもり」になって飛ばしてしまうことを防げます。たとえば、比較演算子の等号は=ではなくて、==です。プログラミングはこういうところに注意して学ばなければいけません。
教科書のサンプルコードをノートに書き写したら、それを今度は自力でフローチャート(UML)に変換してみましょう。そうすることで、自分が本当にそのコードを理解しているのか、確かめることができます。
フローチャートやUMLが素早く正確に描けることは、プログラマーとして働く上で非常に重要なスキルです。それらはソフトウェア設計の基礎となりますし、ソースコードを読めない営業や顧客にとっては貴重な資料となるからです。プロのエンジニアは、COBOLのソースコード10万行を1週間でフローチャートにして、Excelに転載することができます。
ここで一つ注意すべきことがあります。フローチャートを描くときは、必ず専用の定規を用いて描いて下さい。フリーハンドで描いたものは業務ではフローチャートとは認められません。これはまともな企業に就職すれば研修などで必ず習うことですから、今の内に覚えておきましょう。
エンジニアを目指すのであれば、プログラミングだけではなく、Excelの使い方も学びましょう。Excelはエンジニアにとっての万能プラットフォームです。エンジニアはあらゆる作業をExcelで行います。セル結合や罫線を用いて、見栄えの良い資料を作る技術は、エンジニアにとって必須です。
プログラミング学習中であれば、たとえば以下のような題材の資料を作ってみると良いでしょう。
尤も、以上の資料は、ツールを使うことで自動で作成することもできます。たとえば、ソースコードの更新履歴はGitなどのバージョン管理システムを使うことでも管理できます。しかし、それらの資料としてのクオリティは非常に低いため、アマチュアしか使うことはありません。プロを目指す皆さんは、必ずExcelを使いこなせるようになりましょう!VBAの習得も必須です。
以上、プログラミングの勉強法について解説しました。ここからは、実際にソースコードを書くときのコツを紹介していきます。他のプログラマと差をつけることができる技術ですので、意識するようにして下さい。
理想は、aやxなどの一文字です。ただし、これだけだと26文字しか使えないので、a1, a2, ...のように連番でグルーピングすると良いです。
また、変数の宣言と使用箇所が離れた場合に、変数の型がすぐに分かるように、たとえばint型であればi1, i2, ...、string型であればs1, s2, ...のように命名すると、読む人に親切で自分もミスしにくくなります。
変数名を長くするのは、以下のデメリットがあるため、絶対にやめましょう。
多くのプログラミング言語には、クラスや関数といった機能がありますが、これらは基本的にライブラリ提供者などが使う想定の機能であり、一般のプログラマが使うのは好ましくありません。したがって、クラスや関数はなるべく使わないようにして下さい。
不要な関数を作らないためのテクニックには、以下のようなものがあります。
まず、関数の引数に「フラグ」を渡し、関数内部で処理を切り替えれば、1つの関数で複数の処理をすることができます。
function f(i) { switch(i) { case 1: // i = 1のときの処理 break; case 2: // i = 2のときの処理 break; case 3: // i = 3のときの処理 break; // ... } }
この方法は、以下に述べる「変数の寿命を伸ばす」効果もあります。つまり、この関数内で宣言された変数は、すべての処理で共通して使用することができます。
クラスに不要な関数を作らないようにするには、「継承」を用います。複数のクラスで用いる関数を定義したクラスを1つ作っておき、そのクラスを継承すれば、新しいクラスに関数を定義する必要はありません。
理想的には、プログラム内のすべての関数を同一のクラスに定義し、それを継承するべきです。そのようなクラスは俗に「神」と呼ばれ、プログラマからはこの上なく尊ばれています。
class God { f1() { // 関数1 } f2() { // 関数2 } // ... } class C1 extends God { // 何も書かなくても上の関数が使える! } class C2 extends God { // 何も書かなくても上の関数が使える! } // ...
変数は宣言する場所によって、ソースコードのどの範囲から参照できるかが決まっています。この範囲が広いことを、「変数の寿命が長い」と言います。
たとえば、以下のコードのaは、関数定義の外側からは参照することができません。
function f() { var a = 1; return a; }
一方、以下のコードのaは関数の内外どちらからでも参照することができます。
var a = 1; function f() { a = 2; return a; }
せっかく作った変数がすぐに死んでしまうのは、非常にもったいないです。ソースコードの表面には現れませんが、変数を作ったり捨てたりするのには、計算コストがかかります。したがって、寿命の短い変数を作りすぎてしまうと、プログラムが遅くなってしまいます。
また、変数の寿命が長いということは、変数をたくさん作らなくても、1つの変数を色々なところで利用できるということであり、とても便利です。たとえば、上記の前者のコードでは、関数の外部からaの値を参照したくなっても、参照することができません。後者のように書いておけば、プログラムのどの箇所からでも、aの値を参照したり、更新することができます。したがって、変数の寿命を長くするとプログラムを変更しやすくなります。つまり、保守性が上がります。
例外とは、プログラムが予期しない処理をしようとした場合に、プログラムの実行を停止し、呼び出し元にエラーを通知する機能です。たとえば、「test.txt」というファイルを開こうとしても、そのファイルが存在しない場合は、例外となります。
例外が発生すると、プログラムが停止してしまうため、非常に困ります。したがって、プログラマは例外をきちんと処理しなければなりません。
ほとんどのプログラミング言語には、例外処理のための機構があります。たとえば、以下のような構文です。
try { // 例外が発生し得る処理 // ex. ファイルを開く } catch (e) { // 例外が発生したときに、実行する処理 }
例外への対処は実はとても簡単です。是非ここで覚えて下さい。上記のような機構のある言語であれば、catch節の中身を何も書かなければ、例外が発生しても、何事もなくプログラムは動作を続けます。
try { // 例外が発生し得る処理 } catch () {}
全ての例外を潰せば、決して不慮の動作で停止することのないプログラムを作ることができます。ですから、例外が発生し得るコードは、積極的に上記のtry-catch構文を用いて、例外を潰すようにしましょう。
追記:ブコメですでに記事があるという指摘があったので、いまさら投稿しなくてもいいか。
なにかに流用したい人がいるかわからんが好きに使ってくれていい。
A creative member of the Tokyo Olympics opening ceremony music was found to have been a fierce bullying assailant in the past.
Keigo Oyamada (born 1969) became a creative member of the Tokyo Olympics opening ceremony music.
In an interview with a music magazine in the 1990s, He talked about being a perpetrator of bullying as if it were a funny thing.
Interview in the January 1994 issue of the music magazine "Rockin' On Japan 20,000-word interview with Keigo Oyamada"
"Also, the bullying was really bad at my school."
But you said you were the bully.
"Yeah. I bullied him. When I think about it now, it was really awful. I'd like to take this opportunity to apologize (laughs) because I've been bullying him pretty hard."
Did you do something that bad?
"Yes. Yes, it's against the rules of humanity. I would strip them completely naked, wrap a string around them, and make them masturbate. They feed you shit. And backdropping him after he ate shit."
The school he attended was a combination of primary, secondary, high school and university.
The school offers "joint education" where normal children and disabled children are placed in the same class.
A writer who read this interview planned a dialogue between the "bully" and the "bullied", but it did not happen.
It became a personal interview with Keigo Oyamada.
There was a guy named Sawada. He was a very epoch-making guy, and he came to the school when I was in the second grade. It was a shock to the whole school (laughs). When he moved to a new school and introduced himself, he would suddenly say (in a tone that sounded like he had a speech impediment), "I'm Sawada. It's like, "Wow, that's great! Then, on the first day at the new school, I took a dump. It's a felony for elementary school students to take a dump at school, isn't it?
There was a cardboard box or something like that, and I put Sawada in it, tied it all up with duct tape, made air holes in it (laughs), and said, "Hey, Sawada, are you okay? (laughs) Then, with a chalkboard eraser or something, I slapped it around and said, "Poison gas attack! (laughs) Then, I took a blackboard eraser and said, "Poison gas attack! ...? He said something really interesting. I don't know what it was, but he said something like "Mommy" or something like that (laughs), and everyone burst out laughing.
When it comes to his jersey, everyone takes it off, but it's nothing for him to take his dick out, so he just walks around with it out. But he's got a big dick, and it's been that way since elementary school, but in high school it got even bigger (laughs). (laughs) The girls would react to it, so we would take it off on purpose and have him walk down the hallway.
コラッツ予想の計算過程を出力するプログラム書いたんだけどもっと簡単に簡略して書く方法おしえてけろ
public class Calc{ public static void main(String[] args) { for(int i=2; i>0; i++) { int a = i; System.out.println("-----"+ a +"の場合-----"); while(a != 1) { if(a % 2 == 0) { System.out.println(a +" ÷ 2 = "+(a = a / 2)); }else{ System.out.println(a +" × 3 + 1 = "+(a = 3* a +1)); } } } } }
変数や構文などのプログラミングの基礎は覚えた人向けに、ソースコードを書くときのコツを紹介していきます。どれも今日から実践できるものばかりです。他のプログラマと差をつけることができる技術ですので、ぜひ意識するようにして下さい。良い子はまねしないで下さい。
理想は、aやxなどの一文字です。ただし、これだけだと26文字しか使えないので、a1, a2, ...のように連番でグルーピングすると良いです。
また、変数の宣言と使用箇所が離れた場合に、変数の型がすぐに分かるように、たとえばint型であればi1, i2, ...、string型であればs1, s2, ...のように命名すると、読む人に親切で自分もミスしにくくなります。
変数名を長くするのは、以下のデメリットがあるため、絶対にやめましょう。
多くのプログラミング言語には、クラスや関数といった機能がありますが、これらは基本的にライブラリ提供者などが使う想定の機能であり、一般のプログラマが使うのは好ましくありません。したがって、クラスや関数はなるべく使わないようにして下さい。
不要な関数を作らないためのテクニックには、以下のようなものがあります。
まず、関数の引数に「フラグ」を渡し、関数内部で処理を切り替えれば、1つの関数で複数の処理をすることができます。
function f(i) { switch(i) { case 1: // i = 1のときの処理 break; case 2: // i = 2のときの処理 break; case 3: // i = 3のときの処理 break; // ... } }
この方法は、以下に述べる「変数の寿命を伸ばす」効果もあります。つまり、この関数内で宣言された変数は、すべての処理で共通して使用することができます。
クラスに不要な関数を作らないようにするには、「継承」を用います。複数のクラスで用いる関数を定義したクラスを1つ作っておき、そのクラスを継承すれば、新しいクラスに関数を定義する必要はありません。
理想的には、プログラム内のすべての関数を同一のクラスに定義し、それを継承するべきです。そのようなクラスは俗に「神」と呼ばれ、その利便性からプログラマからはこの上なく尊ばれています。
class God { f1() { // 関数1 } f2() { // 関数2 } // ... } class C1 extends God { // 何も書かなくても上の関数が使える! } class C2 extends God { // 何も書かなくても上の関数が使える! } // ...
変数は宣言する場所によって、ソースコードのどの範囲から参照できるかが決まっています。この範囲が広いことを、「変数の寿命が長い」と言います。
たとえば、以下のコードのaは、関数定義の外側からは参照することができません。
function f() { var a = 1; return a; }
一方、以下のコードのaは関数の内外どちらからでも参照することができます。
var a = 1; function f() { a = 2; return a; }
せっかく作った変数がすぐに死んでしまうのは、非常にもったいないです。ソースコードの表面には現れませんが、変数を作ったり捨てたりするのには、計算コストがかかります。したがって、寿命の短い変数を作りすぎてしまうと、プログラムが遅くなってしまいます。
また、変数の寿命が長いということは、変数をたくさん作らなくても、1つの変数を色々なところで利用できるということであり、とても便利です。たとえば、上記の前者のコードでは、関数の外部からaの値を参照したくなっても、参照することができません。後者のように書いておけば、プログラムのどの箇所からでも、aの値を参照したり、更新することができます。したがって、変数の寿命を長くするとプログラムを変更しやすくなります。つまり、保守性が上がります。
例外とは、プログラムが予期しない処理をしようとした場合に、プログラムの実行を停止し、呼び出し元にエラーを通知する機能です。たとえば、「test.txt」というファイルを開こうとしても、そのファイルが存在しない場合は、例外となります。
例外が発生すると、プログラムが停止してしまうため、非常に困ります。したがって、プログラマは例外をきちんと処理しなければなりません。
ほとんどのプログラミング言語には、例外処理のための機構があります。たとえば、以下のような構文です。
try { // 例外が発生し得る処理 // ex. ファイルを開く } catch (e) { // 例外が発生したときに、実行する処理 }
例外への対処は実はとても簡単です。是非ここで覚えて下さい。上記のような機構のある言語であれば、catch節の中身を何も書かなければ、例外が発生しても、何事もなくプログラムは動作を続けます。
try { // 例外が発生し得る処理 } catch () {}
全ての例外を潰せば、決して不慮の動作で停止することのないプログラムを作ることができます。ですから、例外が発生し得るコードは、積極的に上記のtry-catch構文を用いて、例外を潰すようにしましょう。
https://github.com/kokorohamoe/OpenProfile/blob/master/700_sample/Java/Jurina/reader.cpp
int main(int argc,const char*argv[]){
int v;
char buffer[1024];
while(1){
printf("input\n");
scanf("%s%d",buffer,&v);
if(strcmp(buffer,"print")==0)
fprintf(stderr, "public class base{\n"
"public static void main(String[] args){\n"
"int i = %d;\n"
"System.out.println(i);}}\n",v);
}
return 0;
}
cat filename.jurina
print "Hello world";
public class filename{
public static void main(String[] args){
System.out.println("Hello world");
}
}
と出力するプログラムをjurinaと名付けるとする
cat filename.jurina
int i=1;
print i;
public class filename{
public static void main(String[] args){
int i=1;
}
}
Javaに置き換えて出力するだけのJava プリプロセッサである
時間 | 記事数 | 文字数 | 文字数平均 | 文字数中央値 |
---|---|---|---|---|
00 | 96 | 10833 | 112.8 | 41.5 |
01 | 71 | 7854 | 110.6 | 47 |
02 | 45 | 6951 | 154.5 | 67 |
03 | 26 | 3787 | 145.7 | 70.5 |
04 | 14 | 3140 | 224.3 | 52 |
05 | 17 | 1924 | 113.2 | 78 |
06 | 19 | 1521 | 80.1 | 54 |
07 | 44 | 4749 | 107.9 | 43 |
08 | 47 | 7325 | 155.9 | 46 |
09 | 75 | 8094 | 107.9 | 43 |
10 | 88 | 8634 | 98.1 | 41.5 |
11 | 52 | 8150 | 156.7 | 53 |
12 | 81 | 10264 | 126.7 | 41 |
13 | 80 | 7063 | 88.3 | 38 |
14 | 89 | 8035 | 90.3 | 42 |
15 | 71 | 7499 | 105.6 | 37 |
16 | 116 | 13466 | 116.1 | 55.5 |
17 | 187 | 17074 | 91.3 | 43 |
18 | 105 | 13272 | 126.4 | 65 |
19 | 65 | 5845 | 89.9 | 41 |
20 | 133 | 12331 | 92.7 | 40 |
21 | 146 | 15193 | 104.1 | 43.5 |
22 | 140 | 16781 | 119.9 | 42 |
23 | 137 | 19912 | 145.3 | 53 |
1日 | 1944 | 219697 | 113.0 | 46 |
池内(7), afa(3), リアルフォース(3), 赤潮(3), ディスクシステム(3), String(3), 5d2(3), c65(3), 古谷(3), c73(3), 398円(3), 聖火(3), ひろゆき(13), ぶつかり(10), 五輪(17), ぶつかっ(12), 美し(7), ファミマ(5), 意図的(6), ウマ(5), 飲める(5), シン(7), 女性差別(11), 明治(7), 転換(6), お菓子(10), 本屋(6), キーボード(7), 明るい(6), irasutoya(8), 思いつく(5), 素人(20), 英語(28), yahoo(13), c(11), 現象(12), 乗る(10), 狙っ(9), 集まる(9), 潰し(9), オリンピック(12)
■最近のネット見ていると「素人の時代」が終わったんだなと悲しい /20210326175758(35), ■全然使われないダースとかいう単位 /20210327082442(14), ■英語を喋るしか能がない人 /20210327201219(12), ■名前みたいな姓ってどんなのがある? /20210326143830(12), ■癌で死ぬ男と分子標的薬(抗がん剤) /20210326173438(11), ■初代ゼルダの伝説は最高のゲームである。 /20210327082514(11), ■日に日にサウナの雰囲気が悪くなっている /20210326160158(10), ■ブクマカは自らが4610であることを自覚せよ /20210326185842(9), ■いいねやRTを欲しがる創作界隈の人に思うこと /20210327160215(8), ■東京はなにもかにもが高い /20210327090622(7), ■はてなの冷笑系クラスタたち一覧 /20210327175320(7), ■ジェンダーフリーの50年後 /20210327111830(7), ■ガチで人生変えたい どうしたらいいの? /20210327001758(7), ■女性にわざとぶつかりにくる男について /20210327210556(6), ■#werise という反コロナイベントが行われる /20210326191647(6), ■金玉吸って!!😠 /20210327071218(6), ■東山動物園でも行くか /20210327123938(6), ■ /20210327173520(6), ■本末転倒感のする行動 /20210327102411(5), ■アンチフェミとは何か /20210327000305(5), ■昔大好きだったダイの大冒険のリメイクアニメについて思うこと。 /20210327202353(5), ■オリンピックのパートナー≒不買推奨企業リスト になったよね /20210327124416(5), ■フェミニズムってそもそも弱者男性を想定してるのかしら? /20210327000111(5), ■多様性大事っていう人は差別主義者だよね /20210327170749(5), ■凡人がはてな匿名ダイアリーという村を見つけました。 /20210325224726(5), ■全員Amazonのハチャメチャ配達員みたいになればいいのに /20210326182722(5), ■彼女がいないと言い張る男 /20210326130831(5), ■キモい女オタクがツイッターアカウントに絶対書いてること /20210327024609(5), ■小汚い爺が歩きタバコしてた /20210327093929(5)
参考書とかにはアルファベット順って呑気に書いてあるけどこれいわゆるASCII順だよねと思って
(彼らが揃いも揃ってアルファベットだけで構成された単語の比較例だけしか出さず、数字開始あり・空白ありの文字列比較をさせないのは怠慢だと思う)
比較に使ってるメソッドなんだろうと思って、String.CompareToからString.Compareに行ってCompareOptionsを見て、
.NET での文字列の比較に関するベスト プラクティス | Microsoft Docs
うわー、うん、なんか見なかったことにしておく
まぁstringはSystem.Stringのエイリアスだから、stringのほうがいい。
intはSystem.Int32のエイリアスなんだけど、ふつーintを使って、Int32なんて使わないでしょ。
boolとSystem.Booleanも同じかな。
https://stackoverflow.com/questions/7074/what-is-the-difference-between-string-and-string-in-c
7と8。
技術的なところが気になる人はこれだけ読んでくれたらいい
最後に技術的な観点からエアレペルソナが純国産ではないということを指摘する。
RocketChatという海外で開発されたOSSチャットアプリをフォーク、改変したもののよう。
ttps://github.com/RocketChat/Rocket.Chat.ReactNative
ttps://rocket.chat
フォーク元はバリバリ多国籍、外資である。(RocketChat自体は問題のないアプリであり、このエアレペルソナとはフォーク関係を超える関係はないと思われる)
冒頭のこの部分に関してである。
ttps://play.google.com/store/apps/details?id=chat.airlex.reactnative
Google Playで公開されているエアレペルソナのAndroidアプリをリバースエンジニアリングして調べてみた。
ちなみに、エアレペルソナには利用規約のようなものは見当たらず、リバースエンジニアリング禁止条項も無いようだった。
ttps://apps.evozi.com/apk-downloader/
ttps://github.com/pxb1988/dex2jar
この辺を使ってapkをダウンロードし、apkを解凍し、chat.airlex.reactnative/classes.dexをjar fileに変換した。
classes.dexから変換されたjarファイルを展開するとchat/airlex/reactnativeというフォルダ、パッケージが見つかる。
このパッケージ内のファイル(.class、クラス)がエアレペルソナの処理を行うもののようである。
このクラスをJadを使い、デコンパイルしてみた。その結果が以下である。
ちなみにここからapkをアップロードするとdex2jarをしなくてもJavaのソースコードにまでデコンパイルしてくれた。便利。
package chat.airlex.reactnative; import android.content.Context; import com.ammarahmed.mmkv.SecureKeystore; import com.facebook.react.bridge.ReactApplicationContext; import com.tencent.mmkv.MMKV; public class Ejson { private String TOKEN_KEY = "reactnativemeteor_usertoken-"; String cardId; String host; String messageId; String messageType; /* access modifiers changed from: private */ public MMKV mmkv; String msg; String notificationType; String rid; Sender sender; String senderName; String type; public Ejson() { ReactApplicationContext reactApplicationContext = CustomPushNotification.reactApplicationContext; if (reactApplicationContext != null) { MMKV.initialize((Context) reactApplicationContext); new SecureKeystore(reactApplicationContext).getSecureKey(C0617Utils.toHex("com.MMKV.default"), new RNCallback() { public void invoke(Object... objArr) { if (objArr[0] == null) { MMKV unused = Ejson.this.mmkv = MMKV.mmkvWithID("default", 1, objArr[1]); } } }); } } public String getAvatarUri() { if (this.type == null) { return null; } return serverURL() + "/avatar/" + this.sender._id + "?rc_token=" + token() + "&amp;rc_uid=" + userId(); } public String token() { String userId = userId(); MMKV mmkv2 = this.mmkv; return (mmkv2 == null || userId == null) ? "" : mmkv2.decodeString(this.TOKEN_KEY.concat(userId)); } public String userId() { String serverURL = serverURL(); MMKV mmkv2 = this.mmkv; return (mmkv2 == null || serverURL == null) ? "" : mmkv2.decodeString(this.TOKEN_KEY.concat(serverURL)); } public String privateKey() { String serverURL = serverURL(); MMKV mmkv2 = this.mmkv; if (mmkv2 == null || serverURL == null) { return null; } return mmkv2.decodeString(serverURL.concat("-RC_E2E_PRIVATE_KEY")); } public String serverURL() { String str = this.host; return (str == null || !str.endsWith("/")) ? str : str.substring(0, str.length() - 1); } public class Sender { String _id; String username; public Sender() { } } }
フィールド名を見てみると、cardId, host, messageId, messageType, mmkv, msg, notificationType, rid, sender, senderName, typeが存在する。
メソッドには、getAvaterUri、token、userId、privateKey、severURLが存在する。
ところで、RocketChatというOSSのチャットアプリが存在する。
ttps://rocket.chat
そのRoketChatのAndroid実装の中に同名のEjsonというクラスが存在する。
ttps://github.com/RocketChat/Rocket.Chat.ReactNative
ttps://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/android/app/src/play/java/chat/rocket/reactnative/Ejson.java
見比べてみると、フィールドにcardIdが追加されている以外はフィールドやメソッド名、そしてその処理の内容まで一致している。
他にもReplyBroadcastなど、同様のクラスがエアレペルソナに見つかる。
以上のことからエアレペルソナはRocketChatをフォークして、パッケージ名を変えて作られたチャットアプリであり、開発の大部分はRocketChat社の努力と多数のOSSコントリビュータによってなされたものであると思われる。
そもそもこのOSS時代に純だの何だの言っている時点で怪しい。
さて、エアレペルソナがRocketChatをフォークして作られたものであるとすると、気になるのはライセンスである。
RocketChatのOSSライセンスはMITライセンスである。
ttps://github.com/RocketChat/Rocket.Chat.ReactNative/blob/develop/LICENSE
MITライセンスは非常に緩いライセンスであるため、エアレペルソナの様にフォークして別のアプリケーションとして公開することにはおそらく問題がないということは強調しておく。
現状エアレペルソナにログインできておらず(2要素認証のコードが送信されないといった問題が起きている模様)、使用している各OSSのライセンス表示が適切に行われているかまでは調べられていない。
DWindow.jsっていうののプログラムの流れが分からんのだ。
if (arguments.length < 2) min = -Infinity; if (arguments.length < 3) max = Infinity; return (parseInt(value, 10) || 0).clamp(min, max);
これがさっっっぱり分からん。Infinityは何処から出てきた?
10か0かっていうのも、窓の数は最大10って書いてあったが、それが問題なのか?
やりたいのが、これと同じように「変数」の値を設定するとして、
配列分ループして色々確認したいのだが、そもそも配列はどうやってやるん?となってる。
Numberだけでなく、Stringの配列も使う予定だ。うーーーーーーーーーーーん。
javascriptの勉強サイトを確認したら分かるものなのか?
もっとソース貼ろうとしたら、匿名ダイアリーに怒られたので載せられん…。
すまんが、詳しい人教えてくれ。