29449


平仮名を判定しようと、`[あ-ゞ]`という正規表現を書いたのですが、`sed`(GNU sed)では使えませんでした。  
（この正規表現は間違っています。 **平仮名の判定に真似しないで下さい** 。sayuriさんの回答を参照のこと）

[code]

    echo "abcあいう123" |sed -re 's/^[あ-ゞ]+//g'
    # エラーになる: sed: -e expression #1, char 16: Invalid collation character
    
[/code]

GNU系の`awk`や`grep`(`-P`オプション付き)では使えるようなのですが、`sed`はどうも駄目なようです。

`[あ-ゞ]`のような正規表現の代替になる手段や、これがそのまま使える`sed`コマンドなどを探しています。  
（なぜ使えないのか、という疑問もあります）

* * *

Ubuntu16.04で、`en_US.UTF-8` と `ja_JP.UTF-8` のロケールでテストしています。  
GNU sed は PCRE（libpcre.so.3）にリンクされている物でテストしていますが、`libc`のみの物でも再現しました。  
`locale
charmap`の実行結果はテストしている`en_US.UTF-8`と`ja_JP.UTF-8`の環境では両方とも、`UTF-8`になります。


CC BY-SA 3.0
2016-09-27T05:28:59.207
29179
2016-10-20T01:23:25.450
2016-10-10T05:41:29.630
3054
3054
question
正規表現 sed locale
sed で [あ-ゞ] のような日本語の文字範囲を使いたい


手元の環境で試してみました。バージョンは全てGNU sed 4.2.2です。

### MINGW64

  * 全て意図通りの動作

### Debian

  * LANG=en_US.UTF-8 
    * 意図通りの動作
  * LANG=ja_JP.UTF-8 
    * [あ-ん] の場合： 意図通りの動作
    * [あ-ゔ] の場合： エラー「無効な照合文字です」
    * [あ-ゞ] の場合： エラー「無効な範囲終了です」

GNU sedはコンパイルオプションで正規表現エンジンを切り替えることができ、DebianではPCRE
8.35にリンクしていますが、MINGW64ではPCREを使わず（たぶん）標準の正規表現エンジンを使用しています。あとはiconvまわりでしょうか…。

* * *

なお`s/^[あ-ゞ]+//g`ですと`^`行頭にマッチさせようとしています。また`[あ-ゞ]`は **ぁ** （小さい **あ**
）を含んでいません。`s/[ぁ-ゞ]+//g`にすべきかと…。

* * *

コメントから

> GNU sed のソースコードを眺めてみると `echo "abcあいう123" | LC_CTYPE=UTF-8 sed -re
> 's/^[あ-ゞ]+//g'` とすれば良い様です。

というようなことはなく`LANG=ja_JP.UTF-8`もしくは`LANG=en_US.UTF-8`で十分です。正しく設定されているかは

[code]

    $ locale charmap
    UTF-8
    
[/code]

の結果が得られるかで確認できます。（ソースコードを見る限り大文字で`UTF-8`となる必要があります。）


CC BY-SA 3.0
2016-09-27T07:36:44.333
29182
2016-09-27T12:58:26.933
2016-09-27T12:58:26.933
4236
4236
29179
answer


環境変数`LC_COLLATE`に`C.UTF-8`を指定する事で解決しました。

[code]

    echo "abcあいう123" |LC_COLLATE=C.UTF-8 sed -re 's/[ぁ-ゞ]/X/g'
    #=> abcXXX123
    
[/code]

`sed`だけでなく、(`-P`オプション無しの GNU) `grep` や`bash`にも有効で、日本語の文字範囲を使えるようになりました。

[code]

    echo "abcあいう123" |LC_COLLATE=C.UTF-8 grep -oE '[ぁ-ゞ]+'
    #=> あいう
    LC_COLLATE=C.UTF-8 bash -c '[[ abcあいう123 =~ [ぁ-ゞ]+ ]]; echo $BASH_REMATCH'
    #=> あいう
    
[/code]

  * `LC_ALL`が設定されていると、`LC_COLLATE`だけ変えても効果がない
  * `LC_CTYPE`と`LC_COLLATE`に互換性の無い値を指定すると、動作は未定義になる  
という[注意点があります](https://www.gnu.org/software/coreutils/manual/coreutils.html#FOOT2)。

* * *

### `en_US.UTF-8` や `ja_JP.UTF-8` でエラーになった理由

ユニコードでは[平仮名は連続しており](http://www.asahi-
net.or.jp/~ax2s-kmtn/ref/unicode/u3040.html)、当然に正規表現の文字範囲でも連続しているものとして扱われると思っていたのですが、そうではありませんでした。  
[ロケールの`LC_COLLATE`グループ](http://pubs.opengroup.org/onlinepubs/007908799/xbd/locale.html#tag_005_003_002)では文字の順序が定められており、この順序は正規表現でも使用されます。

そして、Ubuntu16.04のロケール定義(`/usr/share/i18n/locales/en_US`、`/usr/share/i18n/locales/ja_JP`)では`LC_COLLATE`で平仮名が連続していませんでした。  
`en_US`には平仮名が含まれていません。  
`ja_JP`には平仮名がありますが、連続しているのは「ぁ」から「ん」までで、「ゔ」はそもそも含まれておらず、「ゞ」などは離れた位置にありました。

sayuriさんの回答のように、指定する文字によって動いたりエラーの種類が変わったりするのは、ここらへんの事情が原因のようです。  
`C.UTF-8`の定義は平仮名を全て含んでおり、文字コード順に並んでいるので、期待通りに動いています。


CC BY-SA 3.0
2016-10-10T05:35:59.627
29449
2016-10-20T01:23:25.450
2016-10-20T01:23:25.450
3054
3054
29179
answer