様々な言語の文字列を部分的に取得する機能の挙動

 substr , sliceといった名前で文字列を部分的に取得する機能が様々な言語に実装されています。これですが第二引数の挙動が違ったり、一見同じ挙動でも数値に対応するスタートやゴールが違ったりで大分曲者です。使う時はしっかりと挙動をテストするべきです。特に複数言語にまたがって開発したり、別言語にプログラムを移植する際には要注意です。この記事ではそういった各言語の文字列を部分的に取得する機能の用例を紹介します。紹介する言語は JavaScript、Python、Ruby、PHP、MySQL、Go言語、Java、C++です。

 以降で言う n 番インデックスとは各文字に割り当てられたインデックスのことです。ABCDEFGと文字があったら0番インデックスはAといった具合です。

string: ABCDEFGH
 index: 01234567

 一つ目は JavaScript です。

const str = "0123456789ABCDEFG";
console.log(str.substr(7, 9)); // 789ABCDEF
console.log(str.substring(7, 9)); // 78
console.log(str.slice(7, 9)); // 78

console.log(str.substring(-1)); // 0123456789ABCDEFG
console.log(str.slice(-1)); // G
console.log(str.substring(-3, -1)); // 空文字列
console.log(str.slice(-3, -1)); // EF

 7, 9 を引数とした時、substr は7番インデックスから9文字分の文字を取得し、slice とsubstring は7番インデックスから9番インデックスまで(9番インデックスは含めない)を取得します。substr は非推奨なメソッドですが Edge、Chrome、Firefoxといった各ブラウザで使えます。 似た名前である substr と substring で挙動が違うのは特に誤りやすいです。ちなみに slice と substring には引数に負の値をとったときの挙動に違いがあります。

 二つ目は Python です。Python ではメソッドが不要です。配列チックに添え字を指定して抽出できます。

if __name__ == '__main__':
    _str = "0123456789ABCDEFG"
    # substr はなし。slice のみ
    print(_str[7:9]) # 78
    print(_str[-3:-1]) # EF

 JavaScript の slice 同様に動きます。

 三つ目は Ruby です。Ruby と Python は似た記法で部分文字列を抽出できますが、その挙動には違いがあります。

str = "0123456789ABCDEFG"
# substr はなし。slice のみ
print str[7..9] # 789
print str[-3..-1] # EFG

 Ruby の場合は終点のインデックスも含めます。7..9と指定したならば7番、8番、9番が抽出されます。

 四つ目はPHPです。

<?php

$str = "0123456789ABCDEFG";
# 組み込みは substr のみ
echo substr($str, 7, 9) . "\n"; // 789ABCDEF
# 無理に slice するなら↓
echo implode('', array_slice(str_split($str), 7, 9)); // 789ABCDEF
echo substr($str, -3, -1) . "\n"; // EF
echo implode('', array_slice(str_split($str), -3, -1)); // EF

 substr と array_slice が同じ挙動です。違う名前でも同じ挙動をするのは JavaScript と同じですが、第二引数の意味はまるで違います。PHPでは取得する文字列の開始位置と取得する長さを指定します。また長さ指定が負の場合、終端からその文字数分の文字が省略されます。

 5つ目は MySQL です。

SELECT SUBSTRING('0123456789ABCDEFG', 7, 9);
-- 6789ABCDE

 取得位置と長さを指定する形式ですが、位置の数え方が他の言語と決定的に異なります。MySQLでは最初の一文字目が1番インデックスになります。

 6つ目は Go 言語です。

package main

import ("fmt")

func main() {
        str := "0123456789ABCDEFG"
        fmt.Println(str[7:9]) // 78
}

 JavaScript、Python同様の始点、終点指定です。

 7つ目は Java です。

import java.util.*;

public class Main {
    public static void main(String[] args) throws Exception {
    String str = "0123456789ABCDEFG";
    String substr = str.substring(7, 9); // 78

    System.out.println(substr);
    }
}

 JavaScript、Python、Go言語同様の始点、終点指定です。

 8つ目はC++です。

#include <iostream>
#include <string>

int main() {
    std::string str = "0123456789ABCDEFG";
    std::string sub_str = str.substr(7, 9);
    std::cout << sub_str << std::endl; // => "789ABCDEF"

    return 0;
}

 PHP同様の始点と長さを指定する形式です。

 文字列を部分的に取得する機能は概ねどの言語でも似た形で呼び出せますが、結果に微妙に差異があったり使えない呼び方があったり同じ名前でも挙動が違ったりです。冒頭の繰り返しですが特にテストが重要です。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG