2017-07-03 82 views
0

我有從多個字段,包括布爾(由postgresql導出爲tf字符)postgresql表導出,我需要將它導入另一個數據庫(monetdb )不會將t/f理解爲bool值。使用awk或其他替換文件中的整個字段值

編輯刪除空間,以反映真實文件方面,避免憤怒的評論 - 以前有位顯示)

id|val_str|bool_1|bool2|bool_3|bool4| 
1|help|t|t|f|t| 
2|test|f|t|f|f| 
... 

正如我不能代替t/f,我需要到外地分離器整合所有occurence在我的模式。 我試圖使用awkFALSETRUEf替換字段t

awk -F'|' '{gsub(/\|t\|/, "|TRUE|"); gsub(/\|f\|/, "|FALSE|"); print;}' 

這是工作部分,如用相同的值(|t|t|)連續的場將具有僅第一發生替換(|TRUE|t| - 如第二次事件實際上是t|而不是|t|)。

id|val_str|bool_1|bool2|bool_3|bool4| 
1|help|TRUE|t|FALSE|TRUE| 
2|test|FALSE|TRUE|FALSE|f| 
... 

表有〜450列,所以我真的不能指定列的列表將被替換,也不能在Postgres的工作,以「改造」布爾列(我可以,但...)。

我可以運行gsub()兩次,但我正在尋找更優雅的方式來匹配所有字段的整個字段內容。

gsub(/^t$/, ...)既沒有幫助,也沒有幫助,因爲我們處於大部分時間的中間位置。

+1

你考慮的可能性,使postgresql輸出所需的格式?我會期待一個標誌或一些其他參數使它容易,它看起來像[沒有這樣的事情,但它仍然有可能](https://stackoverflow.com/questions/28959507/output-yes-no-instead-of- TF換布爾數據型在-的PostgreSQL)。 – Aaron

+0

'[原始文件沒有空格]是什麼意思?如果您發佈的樣本輸入與您的真實數據格式不同,那麼很顯然,請解決這個問題,否則您將得到比所需更復雜的解決方案,或者只是不起作用,任何一種方式都會浪費人們的時間。如果這只是一個完全不相關的陳述,那就擺脫它。 –

+0

我認爲這會更容易閱讀。 – ant1j

回答

1

如果perl是好的,你可以使用lookarounds:

$ cat ip.txt 
id | val_str | bool_1 | bool2 | bool_3 | bool4 | 
1 | help | t | t | f | t | 
2 | test | f | t | f | f | 

$ perl -pe 's/\|\K\h*t\h*(?=\|)/ TRUE /g; s/\|\K\h*f\h*(?=\|)/ FALSE /g' ip.txt 
id | val_str | bool_1 | bool2 | bool_3 | bool4 | 
1 | help | TRUE | TRUE | FALSE | TRUE | 
2 | test | FALSE | TRUE | FALSE | FALSE | 
  • \|\K積極的回顧後,以匹配|
  • \h*可選的橫向空間,刪除,如果在輸入
  • (?=\|)正向前查找實際並不存在匹配|


也可以使用與sed循環。測試上GNU sed 4.2.2,語法可以與其它實施方式

$ sed ':a s/| *t *|/| TRUE |/;ta; :b s/| *f *|/| FALSE |/;tb' ip.txt 
id | val_str | bool_1 | bool2 | bool_3 | bool4 | 
1 | help | TRUE | TRUE | FALSE | TRUE | 
2 | test | FALSE | TRUE | FALSE | FALSE | 
  • :a標籤
  • s/| *t *|/| TRUE |/替代命令
  • ta分支變化標記a只要替代命令成功
  • 類似地對於:b


沒有空格輸入

perl -pe 's/\|\Kt(?=\|)/TRUE/g; s/\|\Kf(?=\|)/FALSE/g' ip.txt 
sed ':a s/|t|/|TRUE|/;ta; :b s/|f|/|FALSE|/;tb' ip.txt 
awk 'BEGIN{FS=OFS="|"} {for(i=1;i<=NF;i++){if($i=="t"){$i="TRUE"} if($i=="f"){$i="FALSE"}} print}' ip.txt 
+0

源文件其實沒有空間。在我看來很好。不熟悉Perl,但我想我可以發送輸出到管道STDOUT? – ant1j

+0

是的,這就像任何其他命令一樣...輸出可以傳送 – Sundeep

+0

那裏又是 - 源文件實際上沒有空間。聽起來就像你要求我們幫助你解決(由於白色空間)難以解決的問題,而不是真正的簡單問題。 –

0

使用sed,它`標準。

sed 's/| *t */| TRUE /g;s/| *f */| FALSE /g'

這告訴sed替代每一子串與管道字符開始,空格未知數量(也許零),t和後跟一個未知的號碼與| TRUE空間的空間;與f相同。

如果線路長度混亂,則通過column -t管道輸出。

+0

這不會適用於所有情況...例如:'echo'abc | t 12 | t |' | sed's/| * t */|真/ g'' – Sundeep

+0

什麼* * * t 12'? – hidefromkgb

+1

假設列數據...您的解決方案不檢查兩側的'|'邊界 – Sundeep

1

假設(根據您的意見),你的輸入文件實際上並不像您發佈的樣品,而是看起來是這樣的:

$ cat file 
id|val_str|bool_1|bool2|bool_3|bool4| 
1|help|t|t|f|t| 
2|test|f|t|f|f| 

那麼所有你需要的是:

$ awk '{while(gsub(/\|t\|/,"|TRUE|")); while(gsub(/\|f\|/,"|FALSE|"));}1' file 
id|val_str|bool_1|bool2|bool_3|bool4| 
1|help|TRUE|TRUE|FALSE|TRUE| 
2|test|FALSE|TRUE|FALSE|FALSE| 

用對於N替換字符串作爲一般的解決方案:

$ awk 'BEGIN{m["f"]="FALSE"; m["t"]="TRUE"} {for (k in m) while(gsub("\\|"k"\\|","|"m[k]"|"));} 1' file 
id|val_str|bool_1|bool2|bool_3|bool4| 
1|help|TRUE|TRUE|FALSE|TRUE| 
2|test|FALSE|TRUE|FALSE|FALSE| 
3

表有〜450列,所以我不能真正指定要更換的列的列表 ,也不能在postgres中對'變換'布爾列進行工作(I 可能但...)。

你可以讓Postgres爲你做的工作。基本查詢產生SELECT列表:

SELECT string_agg(CASE WHEN atttypid = 'bool'::regtype 
         THEN quote_ident(attname) || '::text' 
         ELSE quote_ident(attname) END, ', ' ORDER BY attnum) 
FROM pg_attribute 
WHERE attrelid = 'mytable'::regclass -- provide table name here 
AND attnum > 0 
AND NOT attisdropped; 

主要生產形式的字符串:

col1, "CoL 2", bool1::text, "Bool 2"::text 

的所有標識符正確轉義。列以默認順序排列。複製並執行它。使用COPY導出到文件。 (或psql中的\copy)。性能與導出普通表大致相同。如果您不需要大寫字母省略upper()

爲什麼簡單地轉換爲text就夠了?

關於regclass和轉義標識符正確:

如果你需要用大寫TRUE/FALSE/NULL一個完整的語句,標準SQL轉換符號(沒有冒號::),還是原來的列名,也許一個模式修飾的表名:

SELECT 'SELECT ' 
    || string_agg(CASE WHEN atttypid = 'bool'::regtype 
         THEN format('upper(cast(%1$I AS text)) AS %1$I', attname) 
         ELSE quote_ident(attname) END, ', ' ORDER BY attnum) 
    || ' FROM myschema.mytable;'   -- provide table name twice now 
FROM pg_attribute 
WHERE attrelid = 'myschema.mytable'::regclass 
AND attnum > 0 
AND NOT attisdropped; 

主要生產形式的完整聲明:

SELECT col1, "CoL 2", upper(cast(bool1 AS text) AS bool1, upper(cast("Bool 2" AS text)) AS "Bool 2" FROM myschema.mytable; 
+1

「我可以......」=>現在我可以! DBeaver(JDBC客戶端)抱怨「未預料符號(:)」,但使用'psql'則沒有問題,除了我需要添加列名:'THEN'upper('|| quote_ident(attname)||)。 ':: text)AS'|| quote_ident(attname)'有正確的列名稱。或者移除'upper'。 – ant1j

+0

@ ant1j:我不確定你需要大寫和/或原始列名。至於簡短的轉換符號('col :: text'),可以用SQL標準語法'cast(col AS text)'替換它。考慮上面的更新。 –

+0

對於DBeaver來說,簡短的表示法是正常的,我不知道他爲什麼會抱怨這個問題......謝謝你的更新 – ant1j

相關問題