正規表現のおさらい (5)

正規表現のおさらいシリーズ
その1:http://developer.venture-net.co.jp/entry/2018/06/22/174206
その2:http://developer.venture-net.co.jp/entry/2018/06/29/192116
その3:http://developer.venture-net.co.jp/entry/2018/07/06/185719
その4:http://developer.venture-net.co.jp/entry/2018/07/13/185653

アンカー

例えばこんなファイルがあったとします。 f:id:venturenet:20180810183218p:plain
よくあるのが、「先頭がXXXで始まるパターンを抜き出したい」というケースです。

単に 127\.0\.0\.1 という正規表現では、途中にあらわれる 127.0.0.1 にもマッチしてしまいます。

こんなときに使うのが ^$ です。これはこれまでに登場したメタ文字と異なり、特定の文字にマッチするのではなく位置にマッチします。
それぞれ以下の通りです。

メタ文字 意味
^ テキストの先頭にマッチする
$ テキストの末尾にマッチする


^127\.0\.0\.1 と書けば先頭が 127.0.0.1 で始まっているもののみにマッチしてくれるというわけです。




商談のコピーでは見えていない項目はコピーされない

最近知ったので備忘録。

Salesforce の商談にはコピー機能があります。

f:id:venturenet:20180810181146p:plain

これをコピーすると、

f:id:venturenet:20180810181305p:plain

こうなって、確度や売上月01、数量などの項目がコピーされていることがわかります。

商談のコピーについては、商談をコピーする場合の考慮事項 にて、以下のように説明されています。

メモ 項目に対するアクセス権が「参照のみ」の場合、その項目の値はコピーしたレコードには引き継がれません。

商談をコピーする場合の考慮事項 より

それで、上記から項目へのアクセス権さえあれば、例え画面上に表示されていなくともコピーされるものと思っていたのですが、ページレイアウトに追加されていない項目はコピーされませんでした。

当たり前といえば当たり前のような気もしますが、あるプロジェクトでは商談オブジェクトに様々なフラグをカスタム項目で持たせており、それらは主にトリガなどから参照/更新するもので画面上には表示していないものでした。

あるとき商談をコピーしたときの動作がおかしかったため、調査したところ上記が原因だったというわけです。



Salesforce メモ (ID関連)

Salesforce 使いには常識のことかもしれませんが、ときどき Salesforce に触るくらいのエンジニアには未知の機能や仕様があるため備忘録として残します。

項目のIDを調べる

Web-to-リードなどでname属性に指定するアレです。
SOQLで取得できます。リードの場合は以下の通り。

SELECT DurableId, QualifiedApiName, Label, Length, DataType
FROM FieldDefinition
WHERE EntityDefinition.QualifiedApiName='Lead'


DurableId で Lead.00N10000004Os3x のようなものが取れます。その 00N10000004Os3x が ID。

なお、開発者コンソールから実行する場合は、そのユーザの権限が適用され、項目レベルセキュリティなどで参照できなくなっている場合は結果レコードに現れませんので、注意してください。

オブジェクトのIDを調べる

Salesforce の ID の最初の3桁は エンティティID であり、オブジェクトのレコードであれば最初の3桁でオブジェクトを識別することができます。
標準のオブジェクトについてはこちらで確認できます。

カスタムオブジェクトの場合は、以下のSOQLで調べることができます。

SELECT QualifiedApiName, Label, KeyPrefix
FROM EntityDefinition


KeyPrefix が3桁のオブジェクトIDです。

オブジェクトのIDでそのオブジェクトの情報を表示する

上述の情報を使って、
/<オブジェクトID(キープリフィクス)>/o にアクセスすれば、そのオブジェクトのタブが表示されます。
例えば /001/o にアクセスすれば、取引先のタブが表示されます。これは Salesforce 使いならば常識ですね。

なおタブを作成していない場合は表示することはできません。



Apache のリライトまとめ (2)

備忘録その2。 (.htaccess に書く場合)
内容が間違っている可能性もありますので、ご参考まで。

RewriteBase はリライト後のベースを指定する

昔は RewriteBase が何なのかよくわからず、おまじない的につけていたこともありました。

RewriteBase は、リライト後のURLベースを指定します。例えばサーバ定義にて、

Alias /hoge "C:\temp"


となっていた場合、ホストが hoge.test とすれば、C:\temp\abc.html があれば http://hoge.test/hoge/abc.html としてアクセスできます。

このとき C:\temp\.htaccess の RewriteRule で以下のようにしたとします。(C:\temp\def.html は存在する)

RewriteRule abc.html def.html


すると abc.html にマッチして def.html にリライトされますが、これは意図したようには動作しません。
これは、リライト時には、ローカルパスのプリフィックス(=ベース部分、この例でいえば C:\temp)を除外してルールの適用が行われるためです。
この場合は、以下のように書かなければなりません。

RewriteRule abc.html /hoge/def.html


複数の RewriteRule があるとき、/hoge をいちいちつけるのは面倒ですし、/hoge から /foo に変わった場合には変更するのも手間です。
ここで C:\temp へは /hoge でアクセスしているということを示すために、RewriteBase を使用します。
つまりこうです:

RewriteBase /hoge
RewriteRule abc.html def.html


このようにすると意図どおりに、http://hoge.test/hoge/abc.html へのアクセスで C:\temp\def.html が表示されます。





Apache のリライトまとめ

いつも、「これはどうするんだっけ?」「これは何が来るんだっけ?」と忘れてしまうため、備忘録として残します。 (.htaccess に書く場合)
内容が間違っている可能性もありますので、ご参考まで。

.htaccess に書かれたリライトは、深い階層のものが優先的に適用される

上位のパスでリダイレクトをかけようとしても、下位に .htaccess があってリライトの指定がある場合(RewriteEngine on がある場合)はそちらが優先される。

RewriteRule には正規表現とリライト後のパスを書く

RewriteRule <指定されたパスにマッチさせる正規表現> <リライト後のパス>
ということ。

RewriteRule のすぐ後ろには、指定されたパスにマッチさせるための正規表現を書く

例えば http://hoge.test/abc/ へのアクセスで、/ に .htaccess がある場合は、abc/ とのマッチになる。
http://hoge.test/abc/def/ へのアクセスで、/abc に .htaccess がある場合は、def/ とのマッチになる。
頭にスラッシュはつかない。
したがって http://hoge.test/abc/ へのアクセスで / に .htaccess がある場合は、abc や abc/ や . などがマッチする。/abc にはマッチしない。一部でもマッチすれば適用される。

書くものは正規表現なので、 index.html と書いた場合にはこのドットは正規表現の任意の一文字を表すものであって、ドットそれ自体ではない。 つまり index\.html でもマッチする。

なおURLのルート、例えば http://hoge.test/ へのアクセスにマッチさせたい場合、Rewrite / /top/ などと書いてもマッチしない。
この場合はマッチ対象の文字列は空文字列となるので、.* などでなければマッチしない。

RewriteRule が複数ある場合は上にあるものから順に適用される

そういうルールとなっている。

RewriteRule は、RewriteRule に適合しなくなるまで繰り返し評価される

RewriteRule abc.html def.html # (A)
RewriteRule def.html ghi.html # (B)

となっていたときに abc.html へのアクセスが来ると、内部的にはこう動作する。

  1. abc.html が abc.html と一致するか → 一致するので def.html へリライト--- (A)の評価
  2. def.html が def.html と一致するか → 一致するので ghi.html へリライト --- (B)の評価
  3. ghi.html が abc.html と一致するか → 一致しないのでこの RewriteRule は無視 --- (A)の評価
  4. ghi.html が def.html と一致するか → 一致しないのでこの RewriteRule は無視 --- (B)の評価
  5. すべての RewriteRule に一致しなかったので終了 ghi.html がリライト後のパスとなる

直感的には 2 までで終わりそうだが、上記の通り、適合するものがなくなるまで繰り返し適用される。

RewriteRule の [L] フラグは、上記の評価の繰り返しを止めるものではない

RewriteRule abc.html def.html # (A)
RewriteRule def.html ghi.html [L] # (B)
としても、ghi.html が abc.html と def.html にマッチするかは評価される。

RewriteRule abc.html def.html [L] # (A)
RewriteRule def.html ghi.html # (B)
となっている場合は、(A) の評価後いったんはそこで停止するが、評価は繰り返し行われるため、この場合は結局以下のようになる。

  1. (A) の評価 def.html へリライト --- [L]があるので(B)の評価に進まず、また最初から評価が始まる
  2. (A) の評価 マッチせず
  3. (B) の評価 ghi.html へリライト
  4. (A) の評価 マッチせず
  5. (B) の評価 マッチせず
  6. 終了


RewriteRule の [R] フラグがない場合は内部リダイレクトになる

リダイレクトをしたくてリライトを使うケースも多いが、HTTPのリダイレクトを行うには [R] フラグが必要となる。
RewriteRule abc.html def.html
RewriteRule def.html ghi.html
というルールで abc.html にアクセスした場合は、表示されるコンテンツは ghi.html になるが、ブラウザのアドレス上は abc.html のままであるし、ブラウザから ghi.html へのリクエストが出るわけではない。

リダイレクトしたいだけなら Redirect ディレクティブの使用を検討する

単にページが移動したなどの場合は、リライトを使うまでもなく Redirect ディレクティブで十分なケースもある。




正規表現のおさらい (4)

正規表現のおさらいシリーズ
その1:http://developer.venture-net.co.jp/entry/2018/06/22/174206
その2:http://developer.venture-net.co.jp/entry/2018/06/29/192116
その3:http://developer.venture-net.co.jp/entry/2018/07/06/185719

今回は第4弾です。

後方参照

正規表現は複雑な文字列パターンを探す場合に有用ですが、文字列パターンを置換する場合にも非常に強力に機能します。

丸括弧でくくったものはグループ化されるということは以前におさらいした通りです。このグループ化された部分は、後から参照することができます。

後からというのはいつなのかということになりますが、これは正規表現を実際に利用する環境・プログラミング言語・ソフトウェアによりますが、置換後の指定をするところになります。

例えば JavaScript では、/ (スラッシュ)で囲んだものは正規表現オブジェクトになります。
/[abc]/ とすれば、a か b か c の1文字、ということになります。
そして、文字列の置換を行う場合は文字列オブジェクトの replace メソッドを使用します。

'abcdef'.replace('a', 'b'); とすれば、文字列 abcdef について、a を b に置換する、ということになり、この置換前の文字列には、正規表現を指定することができます。

'abcdef'.replace(/a/, 'b'); とすることもできるというわけです。

つまりこの replace メソッドの2番目の引数が置換後の指定をするところであり、上記ではそれに 'b’ を指定したということになります。


本題です。

ある9桁の数字を、3桁ごとに区切ってハイフンを入れたいとします。例えばこうです。

123456789 → 123-456-789

このような置換を行う場合、まず正規表現はどうなるでしょうか。数字が9桁なので、/[0-9]{9}/ と書くことができます。 しかしここでは3桁ごとにグループ化したいので、

/([0-9]{3})([0-9]{3})([0-9]{3})/ のように書いてみます。これも、「0から9までのどれかが3つきて、その後に0から9までのどれかが3つきて、その後に0から9までのどれかが3つくる」という正規表現なので、9桁の数字にマッチします。

この丸括弧で囲ったグループ化した部分は、置換後の指定で使うことができます。この機能を 後方参照 と呼びます。
JavaScript では、後方参照は $ と数字であらわします。例えば $1 や $2 のようになります。$1 は1つ目のグループ、$2 は2つ目のグループということになります。

まとめると、9桁の数字を3桁ごとに区切ってハイフンを入れるには、以下のようになります。

正規表現:/([0-9]{3})([0-9]{3})([0-9]{3})/
置換後の文字列:$1-$2-$3

JavaScript で書くことこうなります。

var s  = '123456789'.replace(/([0-9]{3})([0-9]{3})([0-9]{3})/, '$1-$2-$3');






正規表現のおさらい (3)

正規表現のおさらいシリーズ
その1:http://developer.venture-net.co.jp/entry/2018/06/22/174206
その2:http://developer.venture-net.co.jp/entry/2018/06/29/192116
その4:http://developer.venture-net.co.jp/entry/2018/07/13/185653

前々回前回正規表現についておさらいしてきました。
今回は最長マッチと最短マッチについておさらいします。

最長マッチ

繰り返しを表現するものとして、?、*、+ がありました。* や + は0/1回以上 の繰り返しにマッチするわけですが、それでは a+ という正規表現は、文字列 "aaaab" のどこにマッチするのでしょうか。
これは aaaa にマッチします。デフォルトでは、可能な限り長くマッチするように動作します。このことを指して、最長マッチ とか 最長一致 と言ったりします。

最短マッチ

最長マッチの逆で、マッチ可能の部分で最も短いところにマッチする指定を 最短マッチ といい、* や + の後ろに ? をつけることで最短マッチになります。
a+? という正規表現は、文字列 "aaaab" の最初の a にマッチします。



上記の通り * や + はデフォルトでは最長マッチなのですが、それでは少し困る場合があります。例えばHTMLコードでaタグを探したいとします。

aタグは、 <a href="/">HOME</a> のように 開始タグ、テキスト、終了タグ からなり、開始タグにはいくつかの name="value" 形式の属性を指定することができます。

単純に考えると、これを抜き出すための正規表現はこのようになります。

<a .+</a>

つまり、
・<a が来て
・そのあとに空白が1つ来て
・そのあとに任意の文字が1つ以上来て
・最後に </a> という終了タグが来る
ということになります。
属性やリンクテキストがどのような文字で構成されるかはわかりませんから、.+ を使ってどのような文字にもマッチさせる試みは正しいように思われます。

しかしこれには落とし穴があります。

<a href="/">HOME</a> <a href="/access">ACCESS</a> <a href="/contact">CONTACT</a> とaタグが3つ並んでいる文字列の場合はどこにマッチするでしょうか。
この場合は、頭の <a から最後の </a> までの全体にマッチしてしまいます。 普通はこのようにマッチさせたいことはなく、それぞれのaタグにマッチさせたいはずです。

なぜこのようになるのかといえば、.+ が </a> にもマッチしてしまうからです。.+ は任意の文字が1回以上ですから、</a> にマッチするのは誤りではありません。 そしてデフォルトでは最長マッチのため、可能な限り長く -- 一番最後の </a> の手前までマッチしてしまうというわけです。

ここで最小マッチが活きます。 <a .+?</a> という正規表現であれば、マッチ可能な最小の長さでマッチするため、狙い通りの <a href="/">HOME</a> にマッチすることになります。