2

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

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

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

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

谢谢。

4

3 回答 3

8

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

你得到一个包含整个文件名的单项数组的原因是你的模式匹配整个文件名,并且匹配一次。

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

如何解决问题...

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

ListLast( filename , '.' )

....仅获取文件扩展名并获取不带扩展名的名称,您可以这样做...

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

这使用前瞻来确保在字符串的末尾.至少有一个非.,但是(因为它是前瞻)它被排除在匹配之外(所以你只能在匹配中获得预扩展部分) .

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

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

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

出于这个原因(以及许多其他原因),我为 CF 创建了一个改进的正则表达式实现,称为 cfRegex,它可以让您直接返回组文本(即不要乱用 mid)。

如果你想使用 cfRegex,你可以像这样使用你的原始模式:

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

或使用命名参数:

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

并且您会返回一个匹配数组,其中每个元素是该匹配的捕获组的数组。

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

如果您只关心获取扩展名和/或排除扩展名的文件名,那么上面的示例就足够了。

于 2012-07-02T23:56:48.137 回答
1

@Peter 的反应很棒,但是这种方法可能比必要的要冗长一些。reMatch()只需对正则表达式稍作调整即可做到这一点。

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

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

    aMatch = reMatch(sRegex, URL.filename);

    writeDump(aMatch);
</cfscript>

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

  • foo.bar
  • .htaccess
  • 约翰 8.15.2012.docx

正则表达式的解释:

^ 从字符串的开头

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

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

    (?: 将这些东西组合在一起,但不要记住它以供反向参考。

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

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

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

    $ 到字符串的末尾

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

于 2012-07-03T07:56:39.810 回答
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>
于 2012-07-19T02:48:05.740 回答