如何使用包含空格的信用卡号?

时间:2009-05-18 00:49:46

标签: java string usability

当检测到未经培训的购物者输入信用卡/借记卡号码时,某些花哨的网站会显示错误对话框,因为信用卡/借记卡卡片上印有空格。是否有可能以某种方式编写一个Java Web应用程序,用空格处理这些数字,就好像它们是正确的一样?

18 个答案:

答案 0 :(得分:80)

我的观点是,拒绝信用卡号码的任何网络应用程序都没有完成任务。当您收到信用卡号码时,可以轻松完成:

String ccNumber = ccNumber.replaceAll("[\\s-]+", "");

删除空格和短划线(有些也使用它们)。然后验证结果。如果您强迫他们删除您可以轻松删除的空格,您只会烦扰您的用户。

至于如何验证,这取决于很多事情,例如您正在使用的Web框架以及您选择的验证选项。例如Struts 1可能会也可能不会使用Apache Commons Validator,而Spring MVC将(可能)使用Spring验证等等。因此,我无法确切地告诉您如何验证,但我可以告诉您要验证的内容

首先,带有空格的CC编号应被拒绝。大多数人会发现:

4123 0987 8876 2939

更容易阅读:

4123098788762939

如果用户错过或输错了数字并且需要找到他或她的信用卡号码验证失败的原因,那么这一点非常重要。这篇文章顶部的replaceAll()涵盖了这种情况。

第二件事是您以正确的方式显示信用卡号码(即使出于安全原因,某些数字已被X替换)。我建议你仔细阅读Anatomy of Credit Card Numbers

该页面为您提供了位数和有效前缀的规则。一个强大的Web应用程序将实现这些,因此您可以在尝试使用它之前判断信用卡号是否无效。最多可能需要30秒(或更长时间)才能将信用卡详细信息提交给付款网关,因此您不应该这样做,直到您确定可以接受付款为止。否则就是提供非常糟糕的用户体验。如果用户失败1-2次而不是等待,用户将有机会放弃。

至于显示它们,取决于数字位数:

  • 16:4组由空格隔开;
  • 15:像American Express卡一样,即4-6-5,每组之间有空格;
  • 14:像Diners Club卡一样,即4-6-4,每组之间有空格;
  • 13:从未见过13,但4-5-4或4-4-5或5-4-4(或可能是3-3-3-4)让人想起。

在提交处理作为标准验证例程的一部分之前,应根据页面中提到的校验和算法验证信用卡号。该页面具有该例程的Java实现。

接受信用卡付款的每个网站都应该以绝对最低的价格执行以上所有操作,或者只是丢弃商家占用的百分比沮丧。

所以简短版本是两个简单的规则:

  1. 用户输入尽可能宽容;和
  2. 在提交之前,尽一切可能验证信用卡详细信息。

答案 1 :(得分:19)

我会去除所有非数字字符,然后在通过Luhn's algorithm之类的真实验证运行用户输入之前检查长度是否有效。

String ccNumber = input.replaceAll("\\D", "");

String input中删除所有非数字。

答案 2 :(得分:11)

网站强迫您以特定格式输入信用卡号(及类似信息) - 严重惹恼我。

那些人只是因为他们(开发者)懒惰而给顾客带来不便。没有理由不以任何提供的格式接受信用卡号码,电话号码等信息。唯一的限制是需要了解如何解释该值。

你不应该在意我是否输入5555-4444-3333-2222或5555444433332222,如果你不喜欢它们,只需删除破折号 - 与空格相同。使用电话号码,除非您要自动拨打该号码,否则您可能根本不关心它的格式,因此除非您必须惹恼您的用户。

答案 3 :(得分:10)

不幸的是,没有。 Java无法满足这些要求,因为在x86芯片上模拟Java虚拟机所涉及的开销很大,没有留下像Perl的正则表达式那样有用的结构的空间,因为它可以做到这一点:

$input =~ s/\D//g;

几年前,Java尝试添加正则表达式,但它们只运行在不再使用的PowerPC芯片上。问题是所有正则表达式都必须作为字符串包含而不是作为第一类语言构造,因此需要加倍反斜杠,但是每个人都知道反斜杠在x86架构的主操作系统上意味着不同的东西。

我的建议是升级到Perl。 Scheme也被称为能够处理这种情况并且在竞争中具有巨大优势,但Scheme仅在LISP机器上运行。

答案 4 :(得分:8)

不幸的是,不知道为什么这些花哨的网站需要向未经训练的购物者显示错误对话框:强制购物者以机器喜欢的格式重新输入他们的号码。

为什么,如果只有机器可以进行“数据处理”,那么机器本身就可以改变数据格式!或者,只要没有“未经训练”的购物者这样的东西!唉!

答案 5 :(得分:4)

您的问题似乎很奇怪,但我认为它应该像运行用户通过验证功能输入的信用卡号一样简单,首先会删除所有空格。

在使用或不使用正则表达式的任何现代语言中,这都是微不足道的。

答案 6 :(得分:4)

易。

  • 您的输入空间是包含所有字符的某些字符集中的字符列表。
  • 您的输出空间是包含仅包含数字的某些字符集中的字符列表。

为了解决这个问题,我们创建了一个只包含数字0到9的中间空间。我们可以为这个有限集创建一个新的枚举。我们称之为我们的手指空间,因为它奇怪地包含与手指相同数量的成员。

然后我们编写两个函数。

  1. 将输入空间转换为手指空间
  2. 将手指空间转换为输出空间
  3. 当我们减少手指空间的输入空间时,我们只删除手指空间中找不到的任何字符。从手指空间转换到输出空间更加容易。我们只是在输出空间中找到相同的数字。

    这个技巧适用于所有字符集。我还没弄明白如何确定某个角色是否与我手指套中的成员相匹配。也许我应该把它作为一个问题发布。

答案 7 :(得分:2)

汤姆,

问题在技术上得到解决,让我们在理论上谈谈它。

这里有两种思想流派。我不认为说“如果用户无法弄清楚这是他们的问题”是一个可以接受的答案。

  1. 坚定您的用户输入,只接受格式正确的信用卡号码。这需要让用户保持在页面上,直到他们把一切都做好。
  2. 通过假设他们的意图并为他们调整输入来更宽容(只需确保给他们一个确认屏幕以验证新输入)。
  3. 在我看来,#2是要走的路,你可以使用正则表达式(如上所述)从cc#字段中提取所有空格,特殊字符等,并防止用户输入再次提供信息。

    无论哪种方式,您都应该告知用户正确的输入表格(即xxxx-xx-xxxx)

    作为一条经验法则,我倾向于欣赏那些处理用户输入方式更优雅的网站。

    有关正则表达式的更多提示,请查看正则表达式。信息

    祝你好运,

    -Robert

答案 8 :(得分:1)

有许多选项,但最合乎逻辑的似乎是只做一个简单的字符串替换,用一个封闭的字符替换所有空格,即''。这会将信用卡字符串减少到只有一长串数字......然后就这样处理

答案 9 :(得分:1)

似乎只有一个人提到了Luhn或mod 10算法

http://en.wikipedia.org/wiki/Luhn_algorithm

答案 10 :(得分:1)

我会假设这是一个真正的问题,即使它看起来像某种巨魔或笑话。

您应该对界面进行建模,以便用户以受控方式本能地执行输入。简单地说,首先询问他们的那种卡,然后在输入表格格式化输入以匹配卡。例如,假设一张16位数的卡,如Visa或Mastercard,显示4个输入框,用空格或短划线分隔,每个输入限制为4个字符,并在用户输入第四个数字后自动移动到系列中的下一个框。

它应该与页面上的内容类似:

  

卡号:
  [1234] - [1234] - [1234] - [1234]

  

卡号:
  [1234] - [123456] - [12345]

答案 11 :(得分:1)

这个网站上的广告...只需49.95美元,你就可以拥有一个与这个在线商店兼容的新特殊键盘。点击此处在购物车中添加新键盘并结帐。退房时请在指定栏位中输入您的信用卡号码。请不要输入数字之间的空格,因为我们的商店不知道如何处理数字之间的空格。

答案 12 :(得分:0)

您可以使用onkeypress事件来验证最后一个字符是否有效,如果不是只是将其删除,甚至可能会闪现一条消息,说明输入了无效字符。这样就永远不会输入无效数字。它还可以自动输入所需格式的间隔字符(空格或 - )。

答案 13 :(得分:0)

我在一家商店里写了这对Perl函数,那时只允许Visa(......在Visa,实际上......)。1998年。

sub mod10_checkdigit
{
    my($acct) = @_;
    die "invalid account number in BRPS::mod10_checkdigit"
        unless $acct =~ m%^\d+$%;
    my(@digits) = split //, $acct;
    my($len) = scalar(@digits);
    print "# ($len) @digits\n" if ($ENV{PERL_BRPS_DEBUG});
    my($i, $sum, $chk);
    my($mul) = (($len % 2) == 1) ? 1 : 2;
    $len--;
    for ($i = 0; $i < $len; $i++)
    {
        my($val) = $mul * $digits[$i];
        # Note that we need the digital root of the value, but $val is not
        # greater than 18 (because $digits[$i] <= 9 and $mul <= 2).
        $val -= 9 if ($val >= 10);
        $sum += $val;
        print "# $i: $digits[$i] * $mul => $val => $sum\n" if ($ENV{PERL_BRPS_DEBUG});
        $mul = 3 - $mul;
    }
    $chk = 10 - ($sum % 10);
    $chk = 0 if ($chk == 10);
    return $chk;
}

sub validate_account
{
    my($acct) = @_;
    # Strip leading and trailing blanks
    $acct =~ s/^\s*(\S.*\S)\s*$/$1/;
    my($clean) = $acct;
    # Check that account number is string of digits, blanks and dashes
    return undef, "account number is not a sequence of digits, blanks and dashes"
        unless $acct =~ m/^[- \d]+$/;
    return undef, "account number is not a Visa account number"
        unless $acct =~ m/^4/;
    # Remove non-digits
    $clean =~ s/\D//g;
    return undef, "account number is neither 13 nor 16 digits"
        unless length($clean) == 16 || length($clean) == 13;
    # Punctuators must be reasonably consistent!
    return undef, "invalid punctuation pattern"
        unless ($acct =~ m/^\d{16}$/o or $acct =~ m/^\d{13}$/o or
                $acct =~ m/^\d{4}[- ]\d{4}[- ]\d{4}[- ]\d{4}$/o or
                $acct =~ m/^\d{4}[- ]\d{3}[- ]\d{3}[- ]\d{3}$/o);
    # Determine check digit
    my($chk) = mod10_checkdigit($clean);
    return undef, "check digit on account number is incorrect"
        unless $clean =~ m/$chk$/;
    return $clean, "ok";
}

允许合理的信用卡号码通过。要概括处理Mastercard,Discover,American Express也不难。

咆哮

就像坚持让我以内部格式输入数据的网站一样。 Dammit - 将数字存储为一个大整数并将其作为纯数字字符串发送;这对计算机来说很好。但是,让我输入可识别的人类易读格式 - 甚至以人类易读的格式重新呈现数据。在处理信用卡号码的网站上存在太多,太多的懒惰。

答案 14 :(得分:0)

如果你的意思是javascript,你可以使用“提前到下一个输入”方法:

这是HTML:

<form id="ccform" action="cc_submit.php" method="post">
    <fieldset id="ccnumber">
        <input id="firstset" type="text" maxlength="4" />
        <input id="secondset" type="text" maxlength="4" />
        <input id="thirdset" type="text" maxlength="4" />
        <input id="fourthset" type="text" maxlength="4" />
    </fieldset>
</form>

这是JS:

var ccfields;

function moveToNext(e) {
    var field = e.currentTarget;
    var chars = field.value.length;
    var setnumb = Number(field.id.substr(3,1)) - 1;
    if(chars >= 4 && setnumb < 3) {
        ccfields[setnumb + 1].focus();
    }
}

window.onload = function() {
    ccfields = document.getElementById("ccnumber").getElementsByTagName("input");
    for (var i = 0; i < ccfields.length; i++) {
        ccfields[i].onkeyup = moveToNext;
    }
};

当然,您需要添加一个检查非数字的函数和一个用于获取四个字段并将它们合并为一个字符串以传递回表单的函数。使用像Jquery这样的js库来确保事件以相同的方式处理并简化遍历输入也是一个不错的主意,这样你就可以使用像“name”这样的属性而不会产生任何混淆。

但一般来说,如果人们看到4个字段,就可以更容易地输入他们的数字,而对于那些认为“我坚果,我必须为每个数字使用我的鼠标”的访问者来说(或者至少我是)很高兴该页面足够聪明,可以知道移动到下一个字段。

答案 15 :(得分:0)

不确定。压缩空间。可能有很多方法可以做到;我很想使用String.split()在空格上分解它,然后连接四个字符串。或者使用StringBuffer.indexOf()和.delteCharAt()。

......或正如Cletus所说,使用replaceAll()。

答案 16 :(得分:0)

解决方案1:如何放入4个可以取4位数字的文本框。就像输入软件的许可证密钥一样。输入空格字符或制表符后,您可以触发框以更改为下一行。

解决方案2:使用上述评论之一中提到的正则表达式。问题在于,如果它是一个Web应用程序,您将容易受到注入攻击。

答案 17 :(得分:0)

Java TM 非常适合服务器端编程,而javascript在客户端可能很有用;例如在验证期间。

有效信用卡号的长度在12(例如Maestro)和19(例如Solo,Switch)之间变化。客户端javascript可以找出卡号是否有效(只有数字(带有破折号或空格),适合发行人权限,校验和是否正确......)并执行“人类可读”的1:1映射(例如

American Express    3400 0100 2000 009

)内部表示,例如

<input ... id="ccid" value="340001002000009">
<input ... id="ccissuer" value="AMEX">

一旦信用卡信息验证在输入期间通过验证,这些值就可以透明地转换为内部表格提交时

可以在网上找到对该事项进行一些检查的普通javascript函数的示例,例如,这里http://www.braemoor.co.uk/software/creditcard.shtml

对答案的描述非常多。