regex返回所有值,而不仅仅是第一次找到的值

mhd8tkvw  于 2021-06-25  发布在  Pig
关注(0)|答案(1)|浏览(437)

我在学拉丁语,正在使用正则表达式。不确定正则表达式是否是语言不可知的,但这里是我要做的。
如果我有一个包含两个字段的表:tweet id和tweet,那么我希望遍历每条tweet并提取最多3条提到的内容。
因此,如果一条tweet出现类似“@tim bla@sam@joe something bla bla”的内容,那么该tweet的行项目将具有tweet id,tim,sam,joe。
原始数据有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;

在那次尝试中,我使用了量词,试图返回tweet{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\u extract()返回一个匹配项的数组。我想在一个行项目上获得提及[0]、提及[1]、提及[2]。

oprakyz7

oprakyz71#

无论何时使用pattern\u extract或pattern\u extract\u all udf,请记住它只是由java处理的纯regex。
通过本地java测试来测试regex更容易。以下是我认为可以接受的正则表达式:

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));
    }
}

对于这个正则表达式,如果至少有一个提及,它将返回三个字段,如果没有找到第二个/第三个提及,则第二个和/或第三个字段为空。
因此,您可以使用以下清管器代码:

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

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

相关问题