スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

PL/pgSQLで文字列に含まれる文字列の位置を調べる

Javaで言うところのindexOfとlastIndexOfがPostgreSQLでほしくなりました。
PostgreSQLにはstrpos(string, substring)という組み込み関数がありますが、開始位置も指定できないし、逆からの検索もできません。
ということで、PL/pgSQLで自作することになりますが、まずlastIndexOfを実現するために文字列を反転する関数を作ります。

CREATE OR REPLACE FUNCTION uv_str_reverse(
p_src text
) RETURNS text AS $$
DECLARE
p_length int;
w_result text = '';
BEGIN
IF p_src IS NULL THEN
RETURN p_src;
END IF;

p_length := length(p_src);
IF 2 > p_length THEN
RETURN p_src;
END IF;

FOR i IN REVERSE p_length..1 LOOP
w_result := w_result || substr(p_src, i, 1);
END LOOP;
RETURN w_result;
END;
$$ LANGUAGE plpgsql;

つぎにこの関数を利用して、本命の位置を検索する関数を作ります。
引数は検索対象の文字列、検索したい文字列、開始位置(1から始まるインデックス)、逆から検索するフラグです。

CREATE OR REPLACE FUNCTION uv_strpos(
p_src text
,p_target text
,p_index int DEFAULT 1
,p_reverse boolean DEFAULT false
) RETURNS int AS $$
DECLARE
w_tmp text;
w_result int;
w_length int;
BEGIN
IF p_src IS NULL or
'' = p_src or
p_target IS NULL or
'' = p_target or
p_reverse IS NULL or
p_index IS NULL or
p_index < 1 or
length(p_src) < p_index
THEN
RETURN 0;
END IF;

IF p_reverse THEN
w_tmp := uv_str_reverse(p_src);
ELSE
w_tmp := p_src;
END IF;

w_length := length(w_tmp);
w_tmp := substr(w_tmp, p_index, w_length - p_index + 1);
w_result := strpos(w_tmp, p_target);

IF w_result <> 0 THEN
IF p_reverse THEN
-- 逆転補正、開始位置分補正、検索文字列補正
RETURN w_length - w_result - p_index - length(p_target) + 3;
ELSE
-- 開始位置分補正
RETURN w_result + p_index - 1;
END IF;
ELSE
RETURN 0;
END IF;
END;
$$ LANGUAGE plpgsql;

実行結果は以下ようになります。

select uv_strpos('aaa/bbb/ccc', '/') → 4
select uv_strpos('aaa/bbb/ccc', '/', 1) → 4
select uv_strpos('aaa/bbb/ccc', '/', 4) → 4
select uv_strpos('aaa/bbb/ccc', '/', 5) → 8
select uv_strpos('aaa/bbb/ccc', '/', 9) → 0
select uv_strpos('aaa/bbb/ccc', '/', 1, true) → 8
select uv_strpos('aaa/bbb/ccc', '/', 2, true) → 8
select uv_strpos('aaa/bbb/ccc', '/', 4, true) → 8
select uv_strpos('aaa/bbb/ccc', '/', 5, true) → 4
select uv_strpos('aaa/bbb/ccc', 'aa') → 1
select uv_strpos('aaa/bbb/ccc', 'aa', 2) → 2
select uv_strpos('aaa/bbb/ccc', 'aa', 3) → 0
select uv_strpos('aaa/bbb/ccc', 'aa', 1, true) → 2

一行入魂サイトにまとめがあります。
スポンサーサイト

COMMENTS

COMMENT FORM

TRACKBACK


この記事にトラックバックする(FC2ブログユーザー)

上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。