VB.NETのRegex.Replace後方参照にて、"#" の文字コードが 50(本来35) になってしまう
VB.NETにて出力する文章に雛形を用意し、その雛形の # に番号を当てはめようとしました。
<script runat="server" language="vb">
function checkcode(s as String) as String
System.Text.Encoding.UTF8.GetBytes(s) ' => 50
System.Text.Encoding.UTF8.GetBytes("#") ' => 35
Dim result as String = "(" + s + ") ###"
result = result.replace("#","XX")
return result
end function
function checkcode2(s as String) as String
Dim result as String = "(" + s + ")"
return result
end function
</script>
<%
body = "XXXXXXXXX Page #/#/# XXXXXXXXX"
Dim reg As New Regex("(#)")
REM Pattern 1
body = reg.replace(body,checkcode("$1"))
REM Pattern 2
body = body.Replace("#","!")
%>
のようなコードを書き、(Pattern 1のとき)
XXXXXXXXX Page (XX) XXXXXX/(XX) XXXXXX/(XX) XXXXXX XXXXXXXXX
という結果を期待しました。しかし、これで得られる結果は
XXXXXXXXX Page (#) XXXXXX/(#) XXXXXX/(#) XXXXXX XXXXXXXXX
でした。そこで、checkcode2 に投げてみると、 (#) が帰ってきます。
が、この時 s に入っている # を GetBytes で取得し、 # 部分の文字コードを見てみると 50 になっているのです。2は 2 なので、期待値でもありません。
そこで、(Pattern 2)で置換してみると、こちらは問題なく置換ができました。
この時の文字コードは 35 で、HTML上で # と打てば # が出てきますので想定どおりです。
何故 Regex.Replace を通すと、 # が 35から50に変わってしまうのでしょうか。
お昼から悩み続けて解決できず・・・よろしくお願いします。
---------------------------------19:00 追記
例えば、 s を強制的に # の文字列に置き換えてみました。
<!doctype html>
<html>
<head>
<script runat="server" language="vb">
function checkcode(s as String) as String
Dim result as String = "(" + s + ") ###"
result = result.replace("#","XX")
return result
end function
function forcesharp(s as String) as String
Dim result as String = "(#) ###"
result = result.replace("#","XX")
return result
end function
</script>
</head>
<body>
<%
Dim body as String = "XXXXXXXXX Page #/#/# XXXXXXXXX"
Dim reg As New Regex("(#)")
%>
<%= reg.replace(body,checkcode("$1")) %>
<hr />
<%= reg.replace(body,forcesharp("$1")) %>
</body>
</html>
結果
XXXXXXXXX Page (#) XXXXXX/(#) XXXXXX/(#) XXXXXX XXXXXXXXX
------------------水平線--------------------
XXXXXXXXX Page (XX) XXXXXX/(XX) XXXXXX/(XX) XXXXXX XXXXXXXXX
forcesharp も checkcode も s には # が入っているはずですが、 s をそのまま使っているcheckcodeは # なのに置換されていません。
一方 forcesharp は s を使わず # の文字を改めて手入力していることも有り、正しく置換されています。
バイトコードに置き換えると、手入力したシャープは 35、パターンマッチで取り出したシャープは 50 となっていますが、そもそも手入力した # を検出しているはずなので # は 35のはず。
--------------------------------問題点が判明しました。
Perl頭で合ったことが原因のようでした。
Perlでは $body=~s/(#)/checkcode($1)/egsi; のように、$1 には # が入ってくるので、思い込みからこのトラブルが発生していました。
reg.replace(body,checkcode("$1"))は #ではなく $1が送られている、が原因でした。
--------------------------------解決策
現在以下のページを参考に、想定していた動作のする手段で続行しています。
https://msdn.microsoft.com/ja-jp/library/system.text.regularexpressions.matchevaluator(v=vs.110).aspx