文字列操作でありますまいか

調べていたら雑多なメモになってしまった。色々な文字列分割。

1. キャメルケースとかスネークケースとか
2. 日本の姓名分割
3. 日本の住所分割
4. 中国の etc..

という雑文です。


## [キャメルケースとスネークケースの文字列変換](https://kagamihoge.hatenablog.com/entry/2017/01/03/225054)
使い方はURL参照。https://kagamihoge.hatenablog.com/entry/2017/01/03/225054
速度計測とか、コーディング内容比較してみようかと思ったのだが、[CamelCase と snake_case を相互変換する](https://qiita.com/toastkidjp/items/3c8f21da085ecaace7c3#%E8%BF%BD%E8%A8%98-jmh-%E3%81%A7%E3%81%AE%E3%83%91%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%B3%E3%82%B9%E3%83%81%E3%82%A7%E3%83%83%E3%82%AF) に既に存在したのでそちら参照のこと。よって以下ソースコードのみ参照のこと。


### Google Guava

https://github.com/google/guava/blob/master/guava/src/com/google/common/base/CaseFormat.java#L84

```java
  private static String firstCharOnlyToUpper(String word) {
    return word.isEmpty()
        ? word
        : Ascii.toUpperCase(word.charAt(0)) + Ascii.toLowerCase(word.substring(1));
  }
```


### Commons Lang

https://github.com/apache/commons-lang/blob/master/src/main/java/org/apache/commons/lang3/StringUtils.java#L7539

```java
    private static String[] splitByCharacterType(final String str, final boolean camelCase) {
        if (str == null) {
            return null;
        }
        if (str.isEmpty()) {
            return ArrayUtils.EMPTY_STRING_ARRAY;
        }
        final char[] c = str.toCharArray();
        final List<String> list = new ArrayList<>();
        int tokenStart = 0;
        int currentType = Character.getType(c[tokenStart]);
        for (int pos = tokenStart + 1; pos < c.length; pos++) {
            final int type = Character.getType(c[pos]);
            if (type == currentType) {
                continue;
            }
            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {
                final int newTokenStart = pos - 1;
                if (newTokenStart != tokenStart) {
                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));
                    tokenStart = newTokenStart;
                }
            } else {
                list.add(new String(c, tokenStart, pos - tokenStart));
                tokenStart = pos;
            }
            currentType = type;
        }
        list.add(new String(c, tokenStart, c.length - tokenStart));
        return list.toArray(ArrayUtils.EMPTY_STRING_ARRAY);
    }
```

### ModeShape

https://github.com/HexarA/Json2Pojo/blob/master/src/org/jboss/dna/common/text/Inflector.java#L325

```java
    public String underscore( String camelCaseWord,
                              char... delimiterChars ) {
        if (camelCaseWord == null) return null;
        String result = camelCaseWord.trim();
        if (result.length() == 0) return "";
        result = result.replaceAll("([A-Z]+)([A-Z][a-z])", "$1_$2");
        result = result.replaceAll("([a-z\\d])([A-Z])", "$1_$2");
        result = result.replace('-', '_');
        if (delimiterChars != null) {
            for (char delimiterChar : delimiterChars) {
                result = result.replace(delimiterChar, '_');
            }
        }
        return result.toLowerCase();
    }
```

### Java Case Converter

https://github.com/toolpage/java-case-converter
https://en.toolpage.org/cat/case-converter
https://github.com/toolpage/java-case-converter/blob/master/src/org/toolpage/util/text/CaseConverter.java#L121

```java
	public static String convertToSnakeCase(String value) {
		String throwAwayChars = "()[]{}=?!.:,-_+\\\"#~/";
		value = value.replaceAll("[" + Pattern.quote(throwAwayChars) + "]", " ");
		value = CaseConverter.convertToStartCase(value);
		return value.trim().replaceAll("\\s+", "_");
	}
```

### Netbeans Case Converter
NetBeansのプラグイン
https://github.com/eviweb/netbeans-case-converter


## 日本の姓名分割
と、英語圏の伝統を調べていたところで、[NameDividerを触媒にパーフェクト湯婆婆を創造する](https://qiita.com/cold-wisteria/items/cab1548d71bec5d8ec50) をふと思い出す。

### NameDivider
https://internet.watch.impress.co.jp/docs/yajiuma/1289735.html
https://github.com/rskmoi/namedivider-python
https://github.com/rskmoi/NameDivider

```py
        example:
        -----------------------------------------------------
        >>> namedivider = NameDivider()
        >>> divided_name = namedivider.divide_name("菅義偉")
        >>> print(divided_name)
        "菅 義偉"
        >>> print(divided_name.to_dict())
        {'family': '菅', 'given': '義偉', 'separator': ' ', 'score': 0.6328842762252201, 'algorithm': 'kanji_feature'}
        -----------------------------------------------------
        """ 
```

### name-divider
Githubを眺めていたところ類似のものが少し出てきたのでこちらも。
https://github.com/iszk/name-divider



## 中国の姓名分割
以上まで調べて、そういえば中国語にもあるのかどうかと思ったところ見つかったのはせいぜい以下。

> 将地址簿中中文名字拆分成姓和名按 Last Name 和 First Name 存储。
(アドレスブックの中国語の名前を姓と名に分割し、姓と名として保存します。)

https://github.com/chengyin/chinese-contact-name-separator

## 中国の名前判定
>mingpipeは、中国の名前の名前マッチャーです。2つの名前を取り、それらが同じエンティティ（人、組織、または場所）を参照できるかどうかを予測します。

>例：佛罗伦萨（フィレンツェ） 翡冷翠（フィリピン） true

https://github.com/hltcoe/mingpipe


## 結論：マルチバイト文字圏の文字列は難しい
以下をオチとして今日の調査は終了。

https://github.com/derek73/python-nameparser
https://github.com/derek73/python-nameparser/issues/83

> The parser seems to parse incorrectly for Chinese names in English. (below uses Malaysia's Chinese name) Names without nickname. Current:

```py

>>> name = HumanName('Tham Jun Hoe')
>>> name
<HumanName : [
        title: ''
        first: 'Tham'
        middle: 'Jun'
        last: 'Hoe'
        suffix: ''
        nickname: ''
]>
Expected:

>>> name = HumanName('Tham Jun Hoe')
>>> name
<HumanName : [
        title: ''
        first: 'Jun Hoe'
        middle: ''
        last: 'Tham'
        suffix: ''
        nickname: ''
]>
```