2012-07-12 52 views
0

我有了2列的CSV文件:一個ID和一個免費的文本列。 ID列包含16個字符的字母數字ID,但它可能不是單元格中存在的唯一數據:它可能是空白單元格或僅包含16個字符的ID的單元格,或者包含一堆內容下面埋在裏面 - 「USER_ID = xxxxxxxxxxxxxxxx」,這的Perl - 搜索CSV和提取特定的字符字符串,緊跟它

我想要的就是以某種方式抽取16個字符的ID從哪個細胞有它。所以,我需要: (一)忽略空白單元格 (二)提取出完整的單元格的內容,如果所有它是連續16個字符的字符串,在 (C)之間沒有空格尋找模式「USER_ID =」和然後提取緊隨其後的16個字符

我看到很多用於模式匹配或查找/替換字符串等的Perl腳本,但我不知道如何執行不同類型的解析/模式搜索和提取一個接一個在同一列上。正如你可能已經認識到的,我對Perl相當陌生。

回答

-1

請提供:(a),它可用於測試解決方案和(b)請儘量提供給你迄今爲止編寫了這個問題代碼的一些示例數據。然而,你可能會想要遍歷你的表的所有行,然後split它進入字段,在特定字段上執行所有的操作,執行業務邏輯,然後寫回所有的東西。

問題(c)通過$idField =~ /user_id=(.{16})/; my $id = $1;

解決如果USER_ID總是出現在一行的開頭,這樣做的伎倆:for (<FILE>) {/^user_id=(.{16})/; ...}

0

那麼我可以爲你安排一個基本的文件和正則表達式可能你所需要的(在八九不離十基本格式爲某人不熟悉perl的)命令:

use strict; 
use warnings; 

open FILE "<:utf8", "myfile.csv"; 
#"slurp" the file into an array, each element is a line 
my @lines = <FILE>; 
my @idArray; 
foreach my $line (@lines){ 
    #make two captures, the first we can ignore and both are optional 
    $line =~ /^(user_id=|)([A-Za-z0-9]{16}|),/; 
    #for display purposes, this is just the second captured group 
    my $id = $2; 
    #if the group actually has something in it, add it to your final array 
    if($id){ push @idArray, $id; } 
} 
0

例如,在下面的例子中只有2號線和3是有效的,所以在小區1(列1)是

  • 字符串究竟是什麼16個字符長,或
  • 有 「用戶= 16charshere」

任何其他無效。

use 5.014; 
use warnings; 

while(<DATA>) { 
    chomp; 
    my($col1, @remainder) = split /\t/; 
    say $2 if $col1 =~ m/^(|user=)(.{16})$/; 
} 
__DATA__ 
ToShort col2 not_valid 
a123456789col2 valid 
user=b123456789col2 valid 
TooLongStringHereSoNotValidOne col2 not_valid 

在這個例子中,列是TAB分隔的。

1

我知道你要(1)跳過含有什麼,或不符合您的規範線。 (2)如果它們是單元格的唯一內容,則捕獲16個非空格字符。 (3)按照字面模式「user_id =」捕獲16個非空格字符。

如果可以捕獲空格字符,如果它們遵循「user_id=」字面值,則可以在適當的位置將\S更改爲.

我的解決方案使用Text::CSV處理處理一個CSV文件的詳細信息。這裏是你將如何做到這一點:

use strict; 
use warnings; 
use autodie; 
use open ':encoding(utf8)'; 
use utf8; 
use feature 'unicode_strings'; 
use Text::CSV; 
binmode STDOUT, ':utf8'; 

my $csv = Text::CSV->new({binary => 1}) 
    or die "Cannot use CSV: " . Text::CSV->error_diag; 

while(my $row = $csv->getline(\*DATA)) { 
    my $column = $row->[0]; 
    if($column =~ m/^(\S{16})$/ || $column =~ m/user_id=(\S{16})/) { 
     print $1, "\n"; 
    } 
} 

__DATA__ 
abcdefghijklmnop 
user_id=abcdefghijklmnop 
abcd fghij lmnop 
randomdatAuser_id=abcdefghijklmnopMorerandomdata 
user_id=abcd fghij lmnop 
randomdatAuser_id=abcd fghij lmnopMorerandomdata 

在自己的代碼,你會不會使用DATA文件句柄來,但我相信你知道如何已經open文件。

CSV是一種格式,看起來很簡單。不要將其高可讀性與解析簡單性混爲一談。處理CSV時,最好使用經過驗證的模塊來提取列。其他解決方案可能會導致引用嵌入的逗號,逃過的逗號,不平衡的引號以及我們的大腦隨時爲我們修復的其他違規行爲,但這會使純正規解決方案變得脆弱。

+0

+1它是更好的答案,因爲我的..;) – jm666 2012-07-12 19:51:05

+0

@ user1521736就跟進了幾個星期後檢查,看看是否這個應答(或其他的一個)是對您有所幫助。 – DavidO 2012-08-10 22:03:45