文字檔的字串長度計算

肥肥
我有一個文件檔,內容如下:


每一行文字均代表一筆 record 每個 column 的組合,沒有用分隔的符號來區隔開每個 column 欄位,
唯一能利用的是每個 column 的固定資料長度,所以每行資料都是對齊的(因為資料長度一樣),
想利用 SYSTEM.IO.StreamReader 以 Encoding.GetEncoding("BIG5") 來讀出資料後再 insert 到 db 內。


但有個問題是,他的長度計算碰到了中文就亂掉了,一般 Data type 當然是以半形英數來計算長度的,
以 StreamReader.readLine 到的字串(中英mix),便無法以固定的資料長度來抓取欄位資料了,
因為他遇到了中文字只會當作是一個字元長度(實際上應該是2個字元才對),如此一來 column 就亂掉了。

目前想到的方案是,readLine 後,再每個字元每個字元判斷他是全形or半形,以此來決定該 column 應該抓取到的字串長度,
但這樣還滿麻煩的(column 欄位不少) ~ 不知道有沒有其它高手可以提供較佳的方法呢 ?

謝謝:D
Susu
每一行都有空白,何不考慮抓空白呢,先讀每一行,然後抓出空白區分欄位~
肥肥
空白並無法作為欄位的區隔 ...

其中的


...... 一個無言呀
官官
System.Text.Encoding.Default.GetBytes(你的字串).Length()

用這個試試看,中文字或全形符號會是兩個字元,即一個中文字(或全形符號)=兩個半型英文字(或半形數字)
剛剛是過中文字和全形符號都可以轉成兩個字元,這是寫在.vb檔中;但如果是日文字就不行了

ex.
Dim gStr as string = "我1"
Response.write ("字串長度 = " & System.Text.Encoding.Default.GetBytes(你的字串).Length()")

畫面印出的結果是
字串長度 = 3
官官
剛忘記改
Response.write ("字串長度 = " & System.Text.Encoding.Default.GetBytes(gStr).Length()")
Gene
我也有類似的問題 ...


廠商給的格式是這樣的方式

1234567890123456789012345678901234567890
---------+---------+---------+---------+
123456 A111111 王小頭 王大頭
123457 A111112 李小炸 李大炸
123458 A111113 哈雷路亞 哈雷機車

代碼1 位置 1-6
代碼2 位置 8-15
名稱1 位置 16-29
名稱2 位置 30-40

我想檢查給的格式是否正確,所以在讀取檔案之後,用確認空白位置的方式來檢查是否正確。
在試著輸出各位置的字元時,我發現在 C# 中,中文字元被判定成 1 個字元,並不是 2 個。

所以空白的位置就不固定,沒辦法作檢查了...
Gene
有點說錯了...

重新說明一下格式, # 代表空白位置
123456#A111111#王小頭#######王大頭######
123457#A111112#李小炸#######李大炸######
123458#A111113#哈雷路亞#####哈雷機車####

代碼1 位置 1-6
代碼2 位置 8-14
名稱1 位置 16-27
名稱2 位置 29-40

空白固定的位置在 7,15,28,我只打算抓這 3 個位置的字元判定是否為空白而已。

我的問題就是不知道怎麼找出 7,15,28 的值...
因為在 C# 中,中文字元被判定成 1 個字元,空白的位置,會因為名稱1的長度不同而變...
如果是:
string s = "123,123,花";
string[] sList = s.Split(s,',');

for(int i=0;i<sList.Lenght;i++
{
MessabgBox.Show(sList[i].Lenght.ToString());
}

得到的結果是:3,3,1

我想表達的是,這樣一來無論是中文字英文字,
計算出來的長度都是一樣,因為你的字串已經以","區隔了,
也不會有因為中文英文長度不同的問題發生!
WilliamHsieh
大家好! 看到這則問題, 剛好最近我遇到也解決了. 看到討論的期間在2005至2008年, 大家也都解決了, 還是避開它?
我處理的方式是用字串Byte方式來讀固定長檔:
例如:
dim str128 as string * 128
dim byte128(127) as byte
dim recno as long
dim field1 as string * 12, field2 as string * 25, field3 as string * 12,...
dim charcode as long
open "InputText.txt" for ramdom as #1 len=128
recno=123 '讀第123筆
'get #1, recno, str128 '這寫法會因中文字變動Length而當掉
get #1,recno,byte128
field1=""
for i = 1 to 12: mid$(field1,i,1) = chr$(byte128(i - 1)): next i '沒中文字的欄位
field2=""
j=0
for i = (12 + 1) to (12 + 25)
charcode = byte128(i -1)
if charcode > 127 then
charcode = (charcode * 256&) + byte128(i)
i = I + 1
end if
j = j + 1
mid$(field2, j, 1) = chrw$(charcode) 'chrw轉入Big5碼中文或ASCII字元
next i
....
'其他欄位依上述概念做轉換即可, 其中含中文字的欄位在VB程式中以Unicode為字碼, 以字串輸出時會轉回Big5碼, 但若要寫到固定長擋案, 還是要用Byte方式來做.



愛唱歌的呆子
真的是很久以前的發問了XD

手癢,提供C#版本解法


            var raw = @""; // 原始多行文字

            var fields = new[] { 30, 30, 40, 20, 10 }; // 要切的欄位定義

            // 解析成要切分的位置
            var idx = 0;
            var fieldsForParsing = fields.Select((f, seq) =>
            {
                var info = new { From = idx, Length = f };
                idx += f;
                return info;
            }).ToArray();

            var result = raw.Replace("\r", "\n").Replace("\n\n", "\n").Split('\n')
                .Select(line => System.Text.Encoding.UTF8.GetBytes(line))
                .Select(lineBytes => fieldsForParsing.Select(f => System.Text.Encoding.UTF8.GetString(lineBytes.Skip(f.From).Take(f.Length).ToArray())).ToArray())
                .ToList();

Allen
https://github.com/WebappAllenKuo/FixLengthParser
我也寫了一支練習
回到頂部