为什么正则表达式将文件名与扩展名分开不适用于ColdFusion?

时间:2012-07-02 22:56:44

标签: regex coldfusion coldfusion-9

我正在尝试在ColdFusion中检索没有扩展名的文件名。我使用以下功能: REMatchNoCase( "(.+?)(\.[^.]*$|$)" , "Doe, John 8.15.2012.docx" );

我希望这会返回一个数组:["Doe, John 8.15.2012","docx"] 但我总是得到一个包含一个元素的数组 - 整个文件名:["Doe, John 8.15.2012.docx"]

我在rexv.org上尝试了上面的正则表达式字符串,它按预期工作,但不在ColdFusion上。我从这个问题得到了字符串:Regex: Get Filename Without Extension in One Shot?

ColdFusion是否使用不同的语法?或者我做错了什么?

感谢。

3 个答案:

答案 0 :(得分:8)

为什么你没有得到预期的结果......

您获得具有整个文件名的单项数组的原因是因为您的模式匹配整个文件名,并匹配一次。

捕获这两个组,但rematch返回匹配数组,而不是捕获组的数组,因此您看不到这些组。

如何解决问题...

如果您正在处理简单文件(即没有.htaccess或类似文件),那么最简单的解决方案就是使用......

ListLast( filename , '.' )

....只获取文件扩展名并获取没有扩展名的名称,你可以做...

rematch( '.+(?=\.[^.]+$)' , filename )

这使用前瞻来确保在字符串末尾有一个.后跟至少一个非.,但是(因为它是一个预测)它从匹配中排除(所以你只能在比赛中得到预扩展部分。

要处理未扩展的文件(例如.htaccessREADME),您可以将上述正则表达式修改为.+(?=(?:\.[^.]+)?$),这基本上会做同样的事情,除非使扩展名可选。但是,没有一种简单的方法来更新ListLast方法(猜测你需要检查len(extension) LT len(filename)-1或类似)。

(可选)访问捕获的组...

如果你想获得实际捕获的组,在CF中最接近的本地方法是使用refind函数,第四个参数设置为true - 但是,这只给你位置和长度 - 要求您使用mid自行提取。

由于这个原因(在许多其他人中),我创建了一个improved regex implementation for CF, called cfRegex,它可以让你直接返回组文本(即没有与中间混乱)。

如果您想使用cfRegex,您可以使用原始模式,如下所示:

RegexMatch( '(.+?)(\.[^.]*$|$)' , filename , 1 , 0 , 'groups' )

或者使用命名参数:

RegexMatch( pattern='(.+?)(\.[^.]*$|$)' , text=filename , returntype='groups' )

您将返回一个匹配数组,每个元素内都是该匹配的捕获组数组。

如果您正在处理捕获的组的大量正则表达式工作,cfRegex肯定比使用CF的re方法更好。

如果你关心的只是获得扩展名和/或扩展名的文件名,那么前面的例子就足够了。

答案 1 :(得分:1)

@彼得的反应非常好,但是这种方法可能比必要时更长。可以使用reMatch()执行此操作,并对正则表达式进行轻微调整。

<cfscript>
    param name="URL.filename";

    sRegex = "^.+?(?=(?:\.[^.]+?)?$)";

    aMatch = reMatch(sRegex, URL.filename);

    writeDump(aMatch);
</cfscript>

这适用于以下文件名模式:

  • foo.bar
  • FOO
  • 的.htaccess
  • John 8.15.2012.docx

正则表达式的解释:

^从字符串的开头

。+?一个或多个(+)字符(。),但最少(?)将与正则表达式的其余部分一起使用。这是文件名。

(?=)展望未来。确保此处的内容出现在字符串中,但实际上并不匹配。这是不返回可能存在的任何文件扩展名的关键位。

(?:将这些东西组合在一起,但不记得它作为后面参考。

。一个点。这是文件名和文件扩展名之间的分隔符。

[^。] +?一个或多个(+)单([])个非点字符(^。),再次匹配尽可能少的(?),这将使正则表达式作为一个整体工作。

? (这是(?:)组之后的那个)。零个或其中一个组:即:零个或一个文件扩展名。

$到字符串的末尾

我只测试了这四种文件名模式,但似乎工作正常。其他人可能会对其进行微调。

答案 2 :(得分:1)

实现相同结果的更多方法。它们都在大致相同的时间内执行。

<cfscript>
str = 'Doe, John 8.15.2012.docx';

// sans regex
arr1 = [
    reverse( listRest( reverse( str ), '.' ) ),
    listLast( str, '.' )
];

// using Java String lastIndexOf()
arr2 = [
    str.substring( 0, str.lastIndexOf( '.' ) ),
    str.substring( str.lastIndexOf( '.' ) + 1 )
];

// using listToArray with non-filename safe character replace
arr3 = listToArray( str.replaceAll( '\.([^\.]+)$', '|$1' ), '|' );
</cfscript>