

UnityC#でアプリを作成しており、  
Android側の入力文字とiPhone側の入力文字を一致させるため、  
C#のRegaxを使ってReplaceしようとしているのですがうまくいきません。

下記のようなコードを書いているのですが、  
Androidの実機で0、1、8などが削除されてしまい  
入力可能な文字が除外されてしまいます。

0=0x30 1=0x31 なので除外対尾にはならないと思うのですが、  
除外される理由がわかっていません。  
ご教授いただけないでしょうか？

■Unicode参考サイト  
<http://www.asahi-net.or.jp/~ax2s-kmtn/ref/unicode/index_u.html>

■除外したい正規表現リスト

[code]

    private static readonly List<string> RegexList = new List<string>()
    {
        "[\u2600-\u26FF]",    // Unicodeのその他の記号(Miscellaneous Symbols)
        "[\u0530-\u058F]",    // Unicodeのアルメニア文字(Armenian)
        "[\u0A00-\u0A7F]",    // Unicodeのグルムキー文字(Gurmukhi)
        "[\uD800-\uDB7F]",    // 上位サロゲート（ファイルなし）(High Surrogates)
        "[\uDB80-\uDBFF]",    // 上位私用サロゲート（ファイルなし）(High Private Use Surrogates)
        "[\uDC00-\uDFFF]",    // 下位サロゲート（ファイルなし）(Low Surrogates)
        "[\uE000-\uF8FF]",    // 私用領域（ファイルなし）(Private Use Area)
        "[¥u{EFF80}-¥u{EFFFF}]",  // 未割り当て（第14面）(Unassigned)
        "[¥u{F0000}-¥u{FFFFF}]",  // 補助私用領域A - 未割り当て（第15面）(Supplementary Private Use Area-A)
        "[¥u{100000}-¥u{10FFFF}]",// 補助私用領域B - 未割り当て（第16面）(Supplementary Private Use Area-B)
    }; 
    
[/code]

■内部処理  
・正規表現リスト内をループして該当すれば空文字にする。  
・inputString はアプリ内でキーボード入力された文字列が入っています。

[code]

    foreach (var regex in RegexList)
    {
        inputString = Regex.Replace(inputString, regex, "");
    }
    
[/code]

■開発環境  
VisualStudio2015  
Unity5.6.3p1


CC BY-SA 3.0
2018-02-19T16:16:05.510
41849
2018-02-21T02:03:10.953
5261
question
c# unity3d 正規表現
正規表現を使ってサロゲートや特殊区分の文字を除外したい


使用しているフォントによっては、どちらも円記号に見えているのかもしれませんが、パターン文字列中最初の`\`はU+005cのバックスラッシュ(Windows用を中心に一部フォントでは円記号で表示される)ですが、後ろ3行の`¥`は普通に円記号U+00A5です。

C#では`\u{...}`という表記は通常の文字列内のエスケープシーケンスとしても、`Regex`パターンのエスケープシーケンスとしても無効なので、苦し紛れに本物円記号に置き換えてしまったのでしょうか?

そもそも、あなたの例の場合4〜6行目の`"[\uD800-\uDB7F]", "[\uDB80-\uDBFF]",
"[\uDC00-\uDFFF]"`で全てのサロゲートが除外されてしまうので、非BMP文字の一部範囲を表すようなパターンは意味がありません。

後ろ3行のパターンはとりあえず削除してしまうべきでしょう。(それであなたの所望する文字が全部削除されるかどうかは別問題ですが。)

[code]

    private static readonly List<string> RegexList = new List<string>()
    {
        "[\u2600-\u26FF]",    // Unicodeのその他の記号(Miscellaneous Symbols)
        "[\u0530-\u058F]",    // Unicodeのアルメニア文字(Armenian)
        "[\u0A00-\u0A7F]",    // Unicodeのグルムキー文字(Gurmukhi)
        "[\uD800-\uDBFF]",    // 上位サロゲート(High Surrogates)
        "[\uDC00-\uDFFF]",    // 下位サロゲート(Low Surrogates)
        "[\uE000-\uF8FF]",    // 私用領域(Private Use Area)
    };
    
[/code]

* * *

ちなみに例えば`[¥u{EFF80}-¥u{EFFFF}]`という正規表現は、`¥`がメタキャラクタとは扱われないし`-`の両側の文字も正しく文字範囲と扱えないので、`[]`内に含まれる全文字にマッチするパターンとなるようで、`0`,
`8` 以外に`E`や`F`なんかも削除されてしまうのではないかと思います。

* * *

サロゲートペアの上位下位全部を指定すると、上記に書いたように全ての非BMP文字が削除されてしまうので、「それでは削除対象が多すぎる！」と言う場合にはもっと具体的に削除対象の文字列を示していただかないと、さてどうするべきかは書けないですね。


CC BY-SA 3.0
2018-02-19T19:32:01.740
41851
2018-02-19T19:32:01.740
13972
41849
answer


> 0=0x30 1=0x31 なので除外対尾にはならないと思うのですが、除外される理由がわかっていません。

OOPerさんが既に指摘されていますが、`"[¥u{EFF80}-¥u{EFFFF}]"`等に含まれている`¥`は単なる円記号U+00A5です。そのためこの正規表現は`"[08EFu{}-¥]"`と解釈され、`0`、`8`、`E`、`F`、`u`、`{`と`}`から`¥`（U+007B～U+00A5）がマッチし、`Replace`によって削除されます。  
プログラムは念じた通りには動かず、記述した通りに動くことを理解してください。

>
[code]

>     "[¥u{EFF80}-¥u{EFFFF}]",  // 未割り当て（第14面）(Unassigned)
>     "[¥u{F0000}-¥u{FFFFF}]",  // 補助私用領域A - 未割り当て（第15面）(Supplementary Private
> Use Area-A)
>     "[¥u{100000}-¥u{10FFFF}]" // 補助私用領域B - 未割り当て（第16面）(Supplementary Private
> Use Area-B)
>  
[/code]

の **意図を汲んで** サロゲートペアに分解すると

  * `\uDB7F\uDF80`～`\uDB7F\uDFFF`
  * `\uDB80\uDC00`～`\uDBBF\uDFFF`
  * `\uDBC0\uDC00`～`\uDBFF\uDFFF`

となります。もちろんこれらの文字は１文字目は上位サロゲート`"[\uD800-\uDB7F]"`と`"[\uDB80-\uDBFF]"`に２文字目は下位サロゲート`"[\uDC00-\uDFFF]"`に包含されているため、あえて指定する必要はありません。

それよりもOOPerさんも指摘されているようにサロゲートペア全体を除外するのは範囲が広すぎるかと思います。一部の漢字まで該当・削除されてしまいます。  
仮にサロゲートペアの範囲を縮小する場合、上位サロゲートを絞り込むことになりますが、その際、上位サロゲートと下位サロゲートを個別に削除した場合、特に下位だけ削除されてしまい上位が残ってしまうと文字列として壊れます。削除するのであれば連続した組み合わせに限定すべきです。

[code]

    private static readonly List<string> RegexList = new List<string>()
    {
        "[\u2600-\u26FF]",                // その他の記号(Miscellaneous Symbols)
        "[\u0530-\u058F]",                // アルメニア文字(Armenian)
        "[\u0A00-\u0A7F]",                // グルムキー文字(Gurmukhi)
        "[\uD800-\uDBFF][\uDC00-\uDFFF]", // サロゲートペア(Surrogates)
        "[\uE000-\uF8FF]",                // 私用領域(Private Use Area)
    };
    
[/code]


CC BY-SA 3.0
2018-02-19T22:11:17.160
41852
2018-02-19T22:11:17.160
4236
41849
answer


下記コードで解決できましたが、UnityのIL2CPPビルドを行うと正規表現によるバリデーションが  
効かなくなるので調査中です。

[code]

    /// <summary>
    /// 入力制限をかける正規表現文字列のリスト
    /// </summary>
    private static readonly List<string> InputBlockRegexList = new List<string>()
    {
        "[\u23F3]",                       // (HOURGLASS WITH FLOWING SAND)
        "[\u25FD-\u25FE]",                // (WHITE MEDIUM SMALL SQUAR)(BLACK MEDIUM SMALL SQUARE)
        "[\u2600-\u26FF]",                // その他の記号(Miscellaneous Symbols)
        "[\u2705]",                       // (WHITE HEAVY CHECK MARK)
        "[\u2714]",                       // (HEAVY CHECK MARK)
        "[\u2764]",                       // (HEAVY BLACK HEART)
        "[\u274C]",                       // (CROSS MARK)
        "[\u274E]",                       // (NEGATIVE SQUARED CROSS MARK)
        "[\u2753-\u2755]",                // (BLACK QUESTION MARK ORNAMENT/WHITE QUESTION MARK ORNAMENT/WHITE EXCLAMATION MARK ORNAMENT)
        "[\u2757]",                       // (HEAVY EXCLAMATION MARK SYMBOL)
        "[\u27BF]",                       // (DOUBLE CURLY LOOP)
        "[\u2795-\u2797]",                // (HEAVY PLUS SIGN)・(HEAVY MINUS SIGN)・(HEAVY DIVISION SIGN)
        "[\u2B50]",                       // (WHITE MEDIUM STAR)
        "[\u2B55]",                       // (HEAVY LARGE CIRCLE)
        "[\u2B1B-\u2B1C]",                // (BLACK LARGE SQUARE)・(WHITE LARGE SQUARE)
        "[\u0530-\u058F]",                // アルメニア文字(Armenian)
        "[\u0A00-\u0A7F]",                // グルムキー文字(Gurmukhi)
        "[\uD800-\uDBFF][\uDC00-\uDFFF]", // サロゲートペア(Surrogates)
        "[\uE000-\uF8FF]",                // 私用領域(Private Use Area)
    };
    
[/code]

■バリデーション実装部

[code]

    /// <summary>
    /// 入力文字制限
    /// </summary>
    /// <param name="inputString">入力文字列</param>
    /// <returns>バリデーション後の文字列</returns>
    public static string InputValueValidate(string inputString)
    {
        // 正規表現リストに基づき
        for (int i =0; i < InputBlockRegexList.Count; i++)
        {
            inputString = Regex.Replace(inputString, InputBlockRegexList[i], "");
        }
        return inputString;
    }
    
[/code]


CC BY-SA 3.0
2018-02-21T02:03:10.953
41883
2018-02-21T02:03:10.953
5261
41849
answer