正则表达式返回所有值,而不仅仅是第一个找到的值

时间:2015-06-05 13:23:24

标签: regex apache-pig

我正在学习Pig Latin并使用正则表达式。不确定正则表达式是否与语言无关,但这是我正在尝试做的事情。

如果我有一个包含两个字段的表:tweet id和tweet,我想查看每条推文并提取所有提及最多3个。

因此,如果推文上的内容类似于“@tim bla @sam @joe something bla bla”那么该推文的订单项将包含推文ID,时间,山姆,乔。

原始数据有twitter ID而不是实际句柄所以这个正则表达式似乎返回提及(.*)@user_(\\S{8})([:| ])(.*)

以下是我的尝试:

a = load 'data.txt' AS (id:chararray, tweet:chararray);
b = foreach a generate id, LOWER(tweet) as tweet;

// filter data so only tweets with mentions
c = FILTER b BY tweet MATCHES '(.*)@user_(\\S{8})([:| ])(.*)';

 // try to pull out the mentions. 
 d = foreach c generate id, 
     REGEX_EXTRACT(tweet, '((.*)@user_(\\S{8})([:| ])(.*)){1}',3) as mention1,
     REGEX_EXTRACT(tweet, '((.*)@user_(\\S{8})([:| ])(.*)){1,2}',3) as mention2,
     REGEX_EXTRACT(tweet, '((.*)@user_(\\S{8})([:| ])(.*)){2,3}',3) as mention3;

e = limit d 20;
dump e;

所以在那次尝试我尝试使用量词,尝试在推文{1},{1,2},{2,3}中返回匹配的第一,第二和第三个实例。

这不起作用,提到1-3只是空的。

所以我尝试改变d:

d = foreach c generate id, 
         REGEX_EXTRACT(tweet, '(.*)@user_(\\S{8})([:| ])(.*)',2) as mention1,
         REGEX_EXTRACT(tweet, '(.*)@user_(\\S{8})([:| ])(.*)@user_(\\S{8})([:| ])(.*)',5) as mention2,
         REGEX_EXTRACT(tweet, '(.*)@user_(\\S{8})([:| ])(.*)@user_(\\S{8})([:| ])(.*)@user_(\\S{8})([:| ])(.*)',8) as mention3,

但是,不是返回提到的每个用户,而是返回相同的提及3次。我曾经预料到,通过再次粘贴表达式,我将获得第二场比赛,并且第三次将其粘贴将获得第三场比赛。

我不确定我是如何设法说出这个问题的,但换句话说,假设函数regex_extract()返回了一系列匹配的术语。我想提一下[0],提及[1],在单个项目中提及[2]。

1 个答案:

答案 0 :(得分:2)

无论何时使用PATTERN_EXTRACT或PATTERN_EXTRACT_ALL udf,请记住它只是由Java处理的纯正则表达式。

通过本地Java测试更容易测试正则表达式。这是我发现可接受的正则表达式:

Pattern p = Pattern.compile("@(\\S+).*?(?:@(\\S+)(?:.*?@(\\S+))?)?");

String input = "So if a tweet goes something like @tim bla @sam @joe @bill something bla bla";
Matcher m = p.matcher(input);
if(m.find()){
    for(int i=0; i<=m.groupCount(); i++){
        System.out.println(i + " -> " + m.group(i));
    }
}

有了这个正则表达式,如果至少有一个提及,它将返回三个字段,如果找不到第二个/第三个提及,则秒和/或第三个为空。

因此,您可以使用以下PIG代码:

d = foreach c generate id, REGEX_EXTRACT_ALL(
         tweet, '@(\\S+).*?(?:@(\\S+)(?:.*?@(\\S+))?)?');

您甚至不需要先过滤数据。