我需要阅读包含转义字符的CSV文件内容。 csv文件规范如下:
1. File Encoding UTF-8
2. First line will contain the header information
3. MS-DOS-style lines that end with (CR/LF) characters (optional for the last line)
4. The delimiter character will be the semi-colon “;”
5. Each record must contain the same number of separated fields.
6. Any field may be quoted (with double quotes).
7. Fields containing a line-break, double-quote, and/or delimiter character should be quoted. (If they are not, the file will likely
be impossible to process correctly).
8. A (double) quote character in a field must be represented by two (double) quote characters.
在PL / SQL中实现此功能的最佳方法是什么。 以下是我目前使用的程序:
PROCEDURE parse_csv(
i_csvline IN VARCHAR2,
p_delim IN VARCHAR2 DEFAULT ',',
p_optionally_enclosed IN VARCHAR2 DEFAULT '"',
o_namelist OUT dimension.NAMELIST )
IS
--
CARRIAGE_RETURN CONSTANT CHAR(1) := chr(13);
LINE_FEED CONSTANT CHAR(1) := chr(10);
--
l_char CHAR(1);
l_lookahead CHAR(1);
l_pos NUMBER := 0;
l_token VARCHAR2(32767) := NULL;
l_token_complete BOOLEAN := false;
l_line_complete BOOLEAN := false;
l_new_token BOOLEAN := true;
l_enclosed BOOLEAN := false;
--
l_lineno NUMBER := 1;
l_columnno NUMBER := 1;
v_namelist dimension.NAMELIST :=dimension.NAMELIST();
BEGIN
LOOP
l_pos := l_pos + 1;
l_char := dbms_lob.substr( i_csvline, 1, l_pos);
EXIT
WHEN l_char IS NULL OR l_pos > dbms_lob.getLength( i_csvline );
IF l_new_token AND l_char = p_optionally_enclosed THEN
l_enclosed := true;
l_pos := l_pos + 1;
l_char := dbms_lob.substr( i_csvline, 1, l_pos);
END IF;
l_new_token := false;
l_lookahead := dbms_lob.substr( i_csvline, 1, l_pos+1 );
IF l_char = p_optionally_enclosed AND l_enclosed THEN
IF l_lookahead = p_optionally_enclosed THEN
l_pos := l_pos + 1;
l_token := l_token || l_lookahead;
elsif l_lookahead = p_delim THEN
l_pos := l_pos + 1;
l_token_complete := true;
ELSE
l_enclosed := false;
END IF;
elsif l_char IN ( CARRIAGE_RETURN, LINE_FEED ) AND NOT l_enclosed THEN
l_token_complete := true;
l_line_complete := true;
IF l_lookahead IN ( CARRIAGE_RETURN, LINE_FEED ) THEN
l_pos := l_pos + 1;
END IF;
elsif l_char = p_delim AND NOT l_enclosed THEN
l_token_complete := true;
elsif l_pos = dbms_lob.getLength( i_csvline ) THEN
l_token := l_token || l_char;
l_token_complete := true;
l_line_complete := true;
ELSE
l_token := l_token || l_char;
END IF;
-- process a new token
IF l_token_complete THEN
v_namelist.EXTEND;
v_namelist(v_namelist.LAST):=l_token;
l_columnno := l_columnno + 1;
l_token := NULL;
l_enclosed := false;
l_new_token := true;
l_token_complete := false;
END IF;
IF l_line_complete THEN
l_lineno := l_lineno + 1;
l_columnno := 1;
l_line_complete := false;
END IF;
END LOOP;
o_namelist:=v_namelist;
END parse_csv;