Skip to content

Instantly share code, notes, and snippets.

@gusribeiro
Last active June 27, 2025 18:25
Show Gist options
  • Select an option

  • Save gusribeiro/263a165db774f5d78251 to your computer and use it in GitHub Desktop.

Select an option

Save gusribeiro/263a165db774f5d78251 to your computer and use it in GitHub Desktop.
Regex para identificar bandeiras do cartão de crédito
Amex: ^3[47][0-9]{13}$
Aura: /^((?!504175))^((?!5067))(^50[0-9])/
Banese Card: '^636117'
Cabal: '(60420[1-9]|6042[1-9][0-9]|6043[0-9]{2}|604400)'
Diners: '(36[0-8][0-9]{3}|369[0-8][0-9]{2}|3699[0-8][0-9]|36999[0-9])
Discover: /^6(?:011|5[0-9]{2})[0-9]{12}/
Elo: /^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|^627780|^63(6297|6368|6369)|^65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8]))/
Fort Brasil: '^628167'
GrandCard: '^605032'
Hipercard: ^606282|^3841(?:[0|4|6]{1})0
JCB: /^(?:2131|1800|35\d{3})\d{11}/
Mastercard: ^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})
Personal Card: '^636085'
Sorocred: '^627892|^636414'
Valecard: '^606444|^606458|^606482'
Visa: ^4[0-9]{15}$
@wanderdevof

Copy link
Copy Markdown

ELO: ^(50(67(0[78]|1[5789]|2[012456789]|3[01234569]|4[0-7]|53|7[4-8])|9(0(0[0-9]|1[34]|2[0-7]|3[0359]|4[01235678]|5[01235789]|6[0-9]|7[01346789]|8[01234789]|9[123479])|1(0[34568]|4[6-9]|5[1-8]|8[356789])|2(2[0-2]|5[78]|6[1-9]|7[0-9]|8[01235678]|90)|357|4(0[7-9]|1[0-9]|2[0-2]|31|5[7-9]|6[0-6]|84)|55[01]|636|7(2[2-9]|6[5-9])))|4(0117[89]|3(1274|8935)|5(1416|7(393|63[12])))|6(27780|36368|5(0(0(3[12356789]|4[0-7]|7[78])|4(0[6-9]|1[0234]|2[2-9]|3[045789]|8[5-9]|9[0-9])|5(0[012346789]|1[0-9]|2[0-9]|3[0178]|5[2-9]|6[0-6]|7[7-9]|8[0-8]|9[1-8])|72[0-7]|9(0[1-9]|1[0-9]|2[0128]|3[89]|4[6-9]|5[0145]|6[235678]|71))|16(5[2-9]|6[0-9]|7[01456789])|50(0[0-9]|1[02345678]|36|5[1267]))))\\d{0,13}$

HIPERCARD: ^606282|^3841(?:[0|4|6]{1})0

MASTERCARD: ^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})

AMEX: ^3[47][0-9]{13}$

VISA: ^4[0-9]{15}$

Atualização 2021

@eamax

eamax commented May 3, 2021

Copy link
Copy Markdown

A Regex pra cartões Aura do @JeffersonTeixeira se saiu mais acertiva nos testes que fiz pra essa bandeira.
Quanto a cartões Elo, tomei a liberdade de diminuir/limpar um pouco a Regex atual, mantendo as mesmas regras. Ficou assim:

/^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|^627780|^63(6297|6368|6369)|^65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8]))/

Se alguém tiver alguma lista de cartões Elo e puder compartilhar e testar, ficarei grato :)

De todos os testes que eu fiz com os regex dessa discussão, esse do diafrit foi o único que passou em todos testes que eu fiz para cartão ELO
regexr.com/5s4ov

Edit: aproveitei e deixei uma grande lista de cartões para teste

@eamax

eamax commented May 3, 2021

Copy link
Copy Markdown

^(4011(78|79)|43(1274|8935)|45(1416|7393|763(1|2))|50(4175|6699|67[0-7][0-9]|9000)|50(9[0-9][0-9][0-9])|627780|63(6297|6368)|650(03([^4])|04([0-9])|05(0|1)|05([7-9])|06([0-9])|07([0-9])|08([0-9])|4([0-3][0-9]|8[5-9]|9[0-9])|5([0-9][0-9]|3[0-8])|9([0-6][0-9]|7[0-8])|7([0-2][0-9])|541|700|720|727|901)|65165([2-9])|6516([6-7][0-9])|65500([0-9])|6550([0-5][0-9])|655021|65505([6-7])|6516([8-9][0-9])|65170([0-4]))

Esse regex da Jumori funcionou igualmente bem ao do comentário anterior, passou em todos os testes.
Esse é de um aviso direto da Elo, me parece mais confiável.

@BrunaoW

BrunaoW commented Jul 20, 2021

Copy link
Copy Markdown

Oi pessoal, o Regex da VISA e Elo citados acabam coincidindo pra esse número de cartão gerado: 4576329166124130, o que está me causando uma dor de cabeça pra pensar numa solução.

Gerei nesse site: https://www.vccgenerator.com/

@rafaelsiq94

Copy link
Copy Markdown

Alguém tem o regex para Credz?

@WestBonner

Copy link
Copy Markdown

Alguém tem o regex para Credz?

Tecnicamente falando, é possível criar o regex para uma grande diversidade de cartões tendo por base o Número de Identificação do Emissor (IIN), também chamado de Número de Identificação Bancária (BIN). Isso significa que o reconhecimento da bandeira do cartão geralmente ocorre após inseridos os 4 ou 6 primeiros números desse cartão.
Eu não conheço o emissor do cartão em questão, mas creio que o BIN seja 6367 60XX XXXX XXXX. Se eu estiver correto, ou seja, se todos os cartões da Credz se iniciarem com os seis números citados acima, gerar um regex é tarefa bem simples, basta ver os exemplos acima.

@WestBonner

Copy link
Copy Markdown

Oi pessoal, o Regex da VISA e Elo citados acabam coincidindo pra esse número de cartão gerado: 4576329166124130, o que está me causando uma dor de cabeça pra pensar numa solução.

Gerei nesse site: https://www.vccgenerator.com/

Oi pessoal, o Regex da VISA e Elo citados acabam coincidindo pra esse número de cartão gerado: 4576329166124130, o que está me causando uma dor de cabeça pra pensar numa solução.

Gerei nesse site: https://www.vccgenerator.com/

Coincidências não deveriam ocorrer. Os emissores de cartões definem números de forma a não haver Coincidências. Provavelmente há algum conflito na formação de alguma das regex acima. Estou a muito tempo longe desse tipo de programação, não acho que eu teria expertise - ou paciência - para encontrar o conflito. Talvez alguém se disponibilize a fazê-lo. No entanto, se ninguém o fizer ou se o conflito persistir, você poderá tentar soluções alternativas. Uma delas é, em caso de um conflito, solicitar ao cliente que informe ele mesmo a bandeira do cartão. Pode não ser a solução ideal, mas nem tudo no mundo é...

@GianAlbino

Copy link
Copy Markdown

Esse Regex já está levando em consideração a quantidade de dígitos?
(Pode ser que seja uma pergunta meio besta, mas não me aventuro muito em Regex, então as vezes me perco rsrs)

@IkaroFox

Copy link
Copy Markdown

Efetuei Alguns testes e o padrão do Visa tbm valida o do Elo, esse é o padrão que utilizei para evitar isso, com um negativo lookahead do Elo.

^(?!504175|506699|5067|509|6500|6501|4011(78|79)|43(1274|8935)|45(1416|7393|763(1|2))|50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|627780|63(6297|6368|6369)|65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8])))4[0-9]{12}(?:[0-9]{3})?$

realmente é grande, mas não acontece mais essa exceção.

@Fer-code

Copy link
Copy Markdown

Boa tarde, pessoal!

Estou precisando de uma ajuda pq tmb não tenho experiência em REGEX, esse que foi informado é para qual bandeira? E em suma, quais seriam para cada bandeira?

Efetuei Alguns testes e o padrão do Visa tbm valida o do Elo, esse é o padrão que utilizei para evitar isso, com um negativo lookahead do Elo.

^(?!504175|506699|5067|509|6500|6501|4011(78|79)|43(1274|8935)|45(1416|7393|763(1|2))|50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|627780|63(6297|6368|6369)|65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8])))4[0-9]{12}(?:[0-9]{3})?$

realmente é grande, mas não acontece mais essa exceção.

@gusribeiro

Copy link
Copy Markdown
Author

@GianAlbino não, não está limitando a quantidade de caracteres.

@Fer-code talvez esteja um pouco desatualizado pois não tive mais tempo de vir aqui atualizar a postagem inicial, mas no início da thread eu separei os regex para cada bandeira.

Essa último post, foi relacionado ao Visa e Elo apenas, pelo que eu pude entender.

@IkaroFox

Copy link
Copy Markdown

@Fer-code o que informei é para o Visa.

pois ao utilizar o regex para Visa : ^4[0-9]{15}$ tambem valida para um cartão Elo e do jeito que informei, não acontece isso.

REGEXR é uma opção muito boa para fazer testes.

@Fer-code

Fer-code commented Nov 14, 2023

Copy link
Copy Markdown

Ola pessoal, fiz as correcoes que vcs falaram. Porem percebi que HIPERCARD esta desatualizado. Por isso fiz um novo validando todos que estao nesse site: "https://bincheck.io/pt/br/itau-unibanco,-s.a./hipercard".


HIPERCARD ATUALIZADO: /^(606282\d{10}(\d{3})?)|(3841\d{12})|(637\d{13})$/


AO TODO:

'AMERICAN_EXPRESS': /^3[47]\d{13}$/,

 'DINERS_CLUB': /^3(?:0[0-5]|[68]\d)\d{11}$/,

'ELO': /(4011|431274|438935|451416|457393|4576|457631|457632|504175|627780|636297|636368|636369|(6503[1-3])|(6500(3[5-9]|4[0-9]|5[0-1]))|(6504(0[5-9]|1[0-9]|2[0-9]|3[0-9]))|(650(48[5-9]|49[0-9]|50[0-9]|51[1-9]|52[0-9]|53[0-7]))|(6505(4[0-9]|5[0-9]|6[0-9]|7[0-9]|8[0-9]|9[0-8]))|(6507(0[0-9]|1[0-8]))|(6507(2[0-7]))|(650(90[1-9]|91[0-9]|920))|(6516(5[2-9]|6[0-9]|7[0-9]))|(6550(0[0-9]|1[1-9]))|(6550(2[1-9]|3[0-9]|4[0-9]|5[0-8]))|(506(699|77[0-8]|7[1-6][0-9))|(509([0-9][0-9][0-9])))/,

 'HIPERCARD': /^(606282\d{10}(\d{3})?)|(3841\d{12})|(637\d{13})$/,

'MASTERCARD': /^5[1-5]\d{14}$|^2(?:2(?:2[1-9]|[3-9]\d)|[3-6]\d\d|7(?:[01]\d|20))\d{12}$/,

 'VISA': /^(?!504175|506699|5067|509|6500|6501|4011(78|79)|43(1274|8935)|45(1416|7393|763(1|2))|50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|627780|63(6297|6368|6369)|65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8])))4[0-9]{12}(?:[0-9]{3})?$/

@IkaroFox

IkaroFox commented Nov 15, 2023

Copy link
Copy Markdown

@Fer-code , show de bola, ficou top viu, vou até utilizar kkk

image

@Fer-code

Copy link
Copy Markdown

@Fer-code , show de bola, ficou top viu, vou até utilizar kkk

image

Valeuuu! Mais atualizações vamos mandando ai :)

@MMortari

Copy link
Copy Markdown

Boa tarde pessoal,

Minha pequena contribuição, segue uma lista com alguns cartões que estou colecionando de alguns provedores para teste.

const cards = {
  // PagSeguro
  // https://dev.pagbank.uol.com.br/reference/cartoes-de-teste
  '4539620659922097': EnumCardBrand.VISA,
  '4929291898380766': EnumCardBrand.VISA,
  '5240082975622454': EnumCardBrand.MASTERCARD,
  '5530062640663264': EnumCardBrand.MASTERCARD,
  '345817690311361': EnumCardBrand.AMEX,
  '372938001199778': EnumCardBrand.AMEX,
  '4514161122113757': EnumCardBrand.ELO,
  '4389350446134811': EnumCardBrand.ELO,
  '6062828598919021': EnumCardBrand.HIPERCARD,
  '6062822916014409': EnumCardBrand.HIPERCARD,
  // https://dev.pagbank.uol.com.br/reference/criar-pagar-pedido-com-3ds-validacao-pagbank
  '4000000000002701': EnumCardBrand.VISA,
  '5200000000001005': EnumCardBrand.MASTERCARD,
  '6505050000001000': EnumCardBrand.ELO,
  '4000000000002503': EnumCardBrand.VISA,
  '5200000000001096': EnumCardBrand.MASTERCARD,
  '6505050000001091': EnumCardBrand.ELO,
  '4000000000002925': EnumCardBrand.VISA,
  '5200000000001013': EnumCardBrand.MASTERCARD,
  '6505050000001018': EnumCardBrand.ELO,
  '4000000000002370': EnumCardBrand.VISA,
  '5200000000001104': EnumCardBrand.MASTERCARD,
  '6505050000001109': EnumCardBrand.ELO,
  // Mercado pago
  // https://www.mercadopago.com.br/developers/pt/docs/checkout-api/additional-content/your-integrations/test/cards
  '5067766783888311': EnumCardBrand.ELO,
  '5031433215406351': EnumCardBrand.MASTERCARD,
  '4235647728025682': EnumCardBrand.VISA,
  '375365153556885': EnumCardBrand.AMEX,
  // Gerados
  // https://www.vccgenerator.org/
  '5098176533461570': EnumCardBrand.ELO,
  '5067349319312260': EnumCardBrand.ELO,
  '5098193894226609': EnumCardBrand.ELO,
  '5091084515027541': EnumCardBrand.ELO,
  '5098177024386094': EnumCardBrand.ELO,
  '4391395999142147': EnumCardBrand.VISA,
  '4103922157715577': EnumCardBrand.VISA,
  '4380208328771358': EnumCardBrand.VISA,
  '4297672575052840': EnumCardBrand.VISA,
  '4380277454970936': EnumCardBrand.VISA,
  '5551555128049017': EnumCardBrand.MASTERCARD,
  '5268003770982262': EnumCardBrand.MASTERCARD,
  '5448382804657501': EnumCardBrand.MASTERCARD,
  '5582852950163914': EnumCardBrand.MASTERCARD,
  '5448384161742298': EnumCardBrand.MASTERCARD,
  '340205640990176': EnumCardBrand.AMEX,
  '340205958483061': EnumCardBrand.AMEX,
  '340205254489929': EnumCardBrand.AMEX,
  '340205493225258': EnumCardBrand.AMEX,
  '340205571301401': EnumCardBrand.AMEX,
};

@GabrielLasso

Copy link
Copy Markdown

Implementei essa função em typescript e testei os cartões que o @MMortari mandou, alguns falharam:

export function getCardBrandName (cardNumber: string): string | null {
  const numbers = cardNumber.replace(/[^0-9]+/g, '')

  const cards = {
    amex: /^3[47][0-9]{13}$/,
    aura: /^((?!504175))^((?!5067))(^50[0-9])/,
    banese_card: /^636117/,
    cabal: /(60420[1-9]|6042[1-9][0-9]|6043[0-9]{2}|604400)/,
    diners: /(36[0-8][0-9]{3}|369[0-8][0-9]{2}|3699[0-8][0-9]|36999[0-9])/,
    discover: /^6(?:011|5[0-9]{2})[0-9]{12}/,
    elo: /^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|^627780|^63(6297|6368|6369)|^65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8]))/,
    fort_brasil: /^628167/,
    grand_card: /^605032/,
    hipercard: /^606282|^3841(?:[0|4|6]{1})0/,
    jbc: /^(?:2131|1800|35\d{3})\d{11}/,
    mastercard: /^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/,
    personal_card: /^636085/,
    sorocred: /^627892|^636414/,
    valecard: /^606444|^606458|^606482/,
    visa: /^4[0-9]{15}$/
  }

  const match = Object.entries(cards).find(([_, value]) => {
    if (value.test(numbers)) {
      return true
    }
    return false
  })

  if (match) {
    return match[0]
  }

  return null
}

6505050000001000: Esperado: Elo. Resultado: Discover
6505050000001091: Esperado: Elo. Resultado: Discover
6505050000001018: Esperado: Elo. Resultado: Discover
6505050000001109: Esperado: Elo. Resultado: Discover
5031433215406351: Esperado: Mastercard. Resultado: Aura
5098176533461570: Esperado: Elo. Resultado: Aura
5098193894226609: Esperado: Elo. Resultado: Aura
5091084515027541: Esperado: Elo. Resultado: Aura
5098177024386094: Esperado: Elo. Resultado: Aura

@GabrielLasso

Copy link
Copy Markdown

Comlementando, os cartões que deram errado passam na REGEX da bandeira esperada, mas também passam na da Discover/Aura. Eu comentei essas duas bandeiras e a maioria passou, só o 5031433215406351 que não está passando na REGEX do mastercard

@IkaroFox

IkaroFox commented Apr 5, 2024

Copy link
Copy Markdown

Implementei essa função em typescript e testei os cartões que o @MMortari mandou, alguns falharam:

export function getCardBrandName (cardNumber: string): string | null {
  const numbers = cardNumber.replace(/[^0-9]+/g, '')

  const cards = {
    amex: /^3[47][0-9]{13}$/,
    aura: /^((?!504175))^((?!5067))(^50[0-9])/,
    banese_card: /^636117/,
    cabal: /(60420[1-9]|6042[1-9][0-9]|6043[0-9]{2}|604400)/,
    diners: /(36[0-8][0-9]{3}|369[0-8][0-9]{2}|3699[0-8][0-9]|36999[0-9])/,
    discover: /^6(?:011|5[0-9]{2})[0-9]{12}/,
    elo: /^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|^627780|^63(6297|6368|6369)|^65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8]))/,
    fort_brasil: /^628167/,
    grand_card: /^605032/,
    hipercard: /^606282|^3841(?:[0|4|6]{1})0/,
    jbc: /^(?:2131|1800|35\d{3})\d{11}/,
    mastercard: /^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/,
    personal_card: /^636085/,
    sorocred: /^627892|^636414/,
    valecard: /^606444|^606458|^606482/,
    visa: /^4[0-9]{15}$/
  }

  const match = Object.entries(cards).find(([_, value]) => {
    if (value.test(numbers)) {
      return true
    }
    return false
  })

  if (match) {
    return match[0]
  }

  return null
}

6505050000001000: Esperado: Elo. Resultado: Discover 6505050000001091: Esperado: Elo. Resultado: Discover 6505050000001018: Esperado: Elo. Resultado: Discover 6505050000001109: Esperado: Elo. Resultado: Discover 5031433215406351: Esperado: Mastercard. Resultado: Aura 5098176533461570: Esperado: Elo. Resultado: Aura 5098193894226609: Esperado: Elo. Resultado: Aura 5091084515027541: Esperado: Elo. Resultado: Aura 5098177024386094: Esperado: Elo. Resultado: Aura

Interessante esse comportamento, vou fazer alguns testes aqui e quem sabe com um negative lookahead ele funcione corretamente, posteriormente comentarei com um retorno ...

@gfucci

gfucci commented Dec 9, 2024

Copy link
Copy Markdown

Comlementando, os cartões que deram errado passam na REGEX da bandeira esperada, mas também passam na da Discover/Aura. Eu comentei essas duas bandeiras e a maioria passou, só o 5031433215406351 que não está passando na REGEX do mastercard

Isso acontece porque o padrão desses cartões ELO realmente batem com o padrão da discover, porém por algum motivo a caixa registrou o BIN antes (não sei como funciona esses registros de BIN). Essas exceções já estão no regex da elo, podemos ver na parte "|6505[0-2][0-9]". Se jogarmos no bincheck.io inicialmente ele também da discover, mas se fizer o POST pra verificar ele irá retornar elo.

pra resolver podemos criar um switch e dar break antes para não continuar a verificação, e sempre verificar o ELO primeiro. Um exemplo em PHP

$bandeira = match (1) {
            preg_match(
                '/^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^504175|^627780|^63(6297|6368|6369)|(65003[5-9]|65004[0-9]|65005[01])|(65040[5-9]|6504[1-3][0-9])|(65048[5-9]|65049[0-9]|6505[0-2][0-9]|65053[0-8])|(65054[1-9]|6505[5-8][0-9]|65059[0-8])|(65070[0-9]|65071[0-8])|(65072[0-7])|(65090[1-9]|6509[1-6][0-9]|65097[0-8])|(65165[2-9]|6516[67][0-9])|(65500[0-9]|65501[0-9])|(65502[1-9]|6550[34][0-9]|65505[0-8])|^(506699|5067[0-6][0-9]|50677[0-8])|^(509[0-8][0-9]{2}|5099[0-8][0-9]|50999[0-9])|^65003[1-3]|^(65003[5-9]|65004\d|65005[0-1])|^(65040[5-9]|6504[1-3]\d)|^(65048[5-9]|65049\d|6505[0-2]\d|65053[0-8])|^(65054[1-9]|6505[5-8]\d|65059[0-8])|^(65070\d|65071[0-8])|^65072[0-7]|^(65090[1-9]|65091\d|650920)|^(65165[2-9]|6516[6-7]\d)|^(65500\d|65501\d)|^(65502[1-9]|6550[3-4]\d|65505[0-8])/', 
                $cartaoNumero
            ) => 'elo',
            preg_match('/^4[0-9]{12}(?:[0-9]{3})?/', $cartaoNumero) => 'visa',
            preg_match('/^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/', $cartaoNumero) => 'mastercard',
            preg_match('/^3[47][0-9]{13}/', $cartaoNumero) => 'amexs',
            preg_match('/^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})/', $cartaoNumero) => 'discover',
            preg_match('/^3(?:0[0-5]|[68][0-9])[0-9]{11}/', $cartaoNumero) => 'diners',
            preg_match('/^(?:2131|1800|35\d{3})\d{11}/', $cartaoNumero) => 'jcb',
            preg_match('/^(606282\d{10}(\d{3})?)|(3841\d{12})|(637\d{13})/', $cartaoNumero) => 'hipercard',
            default => ''
        };

Agora todos os números vão bater corretamente!

Esta bandeira 5031433215406351 no bincheck.io deu que não existe, então pode ser retirada.

@Quost

Quost commented Jan 15, 2025

Copy link
Copy Markdown

Eu pequei os cartões dessa resposta do @MMortari :

Boa tarde pessoal,

Minha pequena contribuição, segue uma lista com alguns cartões que estou colecionando de alguns provedores para teste.

const cards = {
  // PagSeguro
  // https://dev.pagbank.uol.com.br/reference/cartoes-de-teste
  '4539620659922097': EnumCardBrand.VISA,
  '4929291898380766': EnumCardBrand.VISA,
  '5240082975622454': EnumCardBrand.MASTERCARD,
  '5530062640663264': EnumCardBrand.MASTERCARD,
  '345817690311361': EnumCardBrand.AMEX,
  '372938001199778': EnumCardBrand.AMEX,
  '4514161122113757': EnumCardBrand.ELO,
  '4389350446134811': EnumCardBrand.ELO,
  '6062828598919021': EnumCardBrand.HIPERCARD,
  '6062822916014409': EnumCardBrand.HIPERCARD,
  // https://dev.pagbank.uol.com.br/reference/criar-pagar-pedido-com-3ds-validacao-pagbank
  '4000000000002701': EnumCardBrand.VISA,
  '5200000000001005': EnumCardBrand.MASTERCARD,
  '6505050000001000': EnumCardBrand.ELO,
  '4000000000002503': EnumCardBrand.VISA,
  '5200000000001096': EnumCardBrand.MASTERCARD,
  '6505050000001091': EnumCardBrand.ELO,
  '4000000000002925': EnumCardBrand.VISA,
  '5200000000001013': EnumCardBrand.MASTERCARD,
  '6505050000001018': EnumCardBrand.ELO,
  '4000000000002370': EnumCardBrand.VISA,
  '5200000000001104': EnumCardBrand.MASTERCARD,
  '6505050000001109': EnumCardBrand.ELO,
  // Mercado pago
  // https://www.mercadopago.com.br/developers/pt/docs/checkout-api/additional-content/your-integrations/test/cards
  '5067766783888311': EnumCardBrand.ELO,
  '5031433215406351': EnumCardBrand.MASTERCARD,
  '4235647728025682': EnumCardBrand.VISA,
  '375365153556885': EnumCardBrand.AMEX,
  // Gerados
  // https://www.vccgenerator.org/
  '5098176533461570': EnumCardBrand.ELO,
  '5067349319312260': EnumCardBrand.ELO,
  '5098193894226609': EnumCardBrand.ELO,
  '5091084515027541': EnumCardBrand.ELO,
  '5098177024386094': EnumCardBrand.ELO,
  '4391395999142147': EnumCardBrand.VISA,
  '4103922157715577': EnumCardBrand.VISA,
  '4380208328771358': EnumCardBrand.VISA,
  '4297672575052840': EnumCardBrand.VISA,
  '4380277454970936': EnumCardBrand.VISA,
  '5551555128049017': EnumCardBrand.MASTERCARD,
  '5268003770982262': EnumCardBrand.MASTERCARD,
  '5448382804657501': EnumCardBrand.MASTERCARD,
  '5582852950163914': EnumCardBrand.MASTERCARD,
  '5448384161742298': EnumCardBrand.MASTERCARD,
  '340205640990176': EnumCardBrand.AMEX,
  '340205958483061': EnumCardBrand.AMEX,
  '340205254489929': EnumCardBrand.AMEX,
  '340205493225258': EnumCardBrand.AMEX,
  '340205571301401': EnumCardBrand.AMEX,
};

E usei os regex da última resposta, conforme o @gfucci colocou em sua resposta:

Comlementando, os cartões que deram errado passam na REGEX da bandeira esperada, mas também passam na da Discover/Aura. Eu comentei essas duas bandeiras e a maioria passou, só o 5031433215406351 que não está passando na REGEX do mastercard

Isso acontece porque o padrão desses cartões ELO realmente batem com o padrão da discover, porém por algum motivo a caixa registrou o BIN antes (não sei como funciona esses registros de BIN). Essas exceções já estão no regex da elo, podemos ver na parte "|6505[0-2][0-9]". Se jogarmos no bincheck.io inicialmente ele também da discover, mas se fizer o POST pra verificar ele irá retornar elo.

pra resolver podemos criar um switch e dar break antes para não continuar a verificação, e sempre verificar o ELO primeiro. Um exemplo em PHP

$bandeira = match (1) {
            preg_match(
                '/^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^504175|^627780|^63(6297|6368|6369)|(65003[5-9]|65004[0-9]|65005[01])|(65040[5-9]|6504[1-3][0-9])|(65048[5-9]|65049[0-9]|6505[0-2][0-9]|65053[0-8])|(65054[1-9]|6505[5-8][0-9]|65059[0-8])|(65070[0-9]|65071[0-8])|(65072[0-7])|(65090[1-9]|6509[1-6][0-9]|65097[0-8])|(65165[2-9]|6516[67][0-9])|(65500[0-9]|65501[0-9])|(65502[1-9]|6550[34][0-9]|65505[0-8])|^(506699|5067[0-6][0-9]|50677[0-8])|^(509[0-8][0-9]{2}|5099[0-8][0-9]|50999[0-9])|^65003[1-3]|^(65003[5-9]|65004\d|65005[0-1])|^(65040[5-9]|6504[1-3]\d)|^(65048[5-9]|65049\d|6505[0-2]\d|65053[0-8])|^(65054[1-9]|6505[5-8]\d|65059[0-8])|^(65070\d|65071[0-8])|^65072[0-7]|^(65090[1-9]|65091\d|650920)|^(65165[2-9]|6516[6-7]\d)|^(65500\d|65501\d)|^(65502[1-9]|6550[3-4]\d|65505[0-8])/', 
                $cartaoNumero
            ) => 'elo',
            preg_match('/^4[0-9]{12}(?:[0-9]{3})?/', $cartaoNumero) => 'visa',
            preg_match('/^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/', $cartaoNumero) => 'mastercard',
            preg_match('/^3[47][0-9]{13}/', $cartaoNumero) => 'amexs',
            preg_match('/^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})/', $cartaoNumero) => 'discover',
            preg_match('/^3(?:0[0-5]|[68][0-9])[0-9]{11}/', $cartaoNumero) => 'diners',
            preg_match('/^(?:2131|1800|35\d{3})\d{11}/', $cartaoNumero) => 'jcb',
            preg_match('/^(606282\d{10}(\d{3})?)|(3841\d{12})|(637\d{13})/', $cartaoNumero) => 'hipercard',
            default => ''
        };

Agora todos os números vão bater corretamente!

Esta bandeira 5031433215406351 no bincheck.io deu que não existe, então pode ser retirada.

Aparentemente está falhando para alguns ainda... Olha o resultado que eu tive:

image

@GabrielLasso

Copy link
Copy Markdown

Comlementando, os cartões que deram errado passam na REGEX da bandeira esperada, mas também passam na da Discover/Aura. Eu comentei essas duas bandeiras e a maioria passou, só o 5031433215406351 que não está passando na REGEX do mastercard

Isso acontece porque o padrão desses cartões ELO realmente batem com o padrão da discover, porém por algum motivo a caixa registrou o BIN antes (não sei como funciona esses registros de BIN). Essas exceções já estão no regex da elo, podemos ver na parte "|6505[0-2][0-9]". Se jogarmos no bincheck.io inicialmente ele também da discover, mas se fizer o POST pra verificar ele irá retornar elo.

pra resolver podemos criar um switch e dar break antes para não continuar a verificação, e sempre verificar o ELO primeiro. Um exemplo em PHP

$bandeira = match (1) {
            preg_match(
                '/^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^504175|^627780|^63(6297|6368|6369)|(65003[5-9]|65004[0-9]|65005[01])|(65040[5-9]|6504[1-3][0-9])|(65048[5-9]|65049[0-9]|6505[0-2][0-9]|65053[0-8])|(65054[1-9]|6505[5-8][0-9]|65059[0-8])|(65070[0-9]|65071[0-8])|(65072[0-7])|(65090[1-9]|6509[1-6][0-9]|65097[0-8])|(65165[2-9]|6516[67][0-9])|(65500[0-9]|65501[0-9])|(65502[1-9]|6550[34][0-9]|65505[0-8])|^(506699|5067[0-6][0-9]|50677[0-8])|^(509[0-8][0-9]{2}|5099[0-8][0-9]|50999[0-9])|^65003[1-3]|^(65003[5-9]|65004\d|65005[0-1])|^(65040[5-9]|6504[1-3]\d)|^(65048[5-9]|65049\d|6505[0-2]\d|65053[0-8])|^(65054[1-9]|6505[5-8]\d|65059[0-8])|^(65070\d|65071[0-8])|^65072[0-7]|^(65090[1-9]|65091\d|650920)|^(65165[2-9]|6516[6-7]\d)|^(65500\d|65501\d)|^(65502[1-9]|6550[3-4]\d|65505[0-8])/', 
                $cartaoNumero
            ) => 'elo',
            preg_match('/^4[0-9]{12}(?:[0-9]{3})?/', $cartaoNumero) => 'visa',
            preg_match('/^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/', $cartaoNumero) => 'mastercard',
            preg_match('/^3[47][0-9]{13}/', $cartaoNumero) => 'amexs',
            preg_match('/^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})/', $cartaoNumero) => 'discover',
            preg_match('/^3(?:0[0-5]|[68][0-9])[0-9]{11}/', $cartaoNumero) => 'diners',
            preg_match('/^(?:2131|1800|35\d{3})\d{11}/', $cartaoNumero) => 'jcb',
            preg_match('/^(606282\d{10}(\d{3})?)|(3841\d{12})|(637\d{13})/', $cartaoNumero) => 'hipercard',
            default => ''
        };

Agora todos os números vão bater corretamente!

Esta bandeira 5031433215406351 no bincheck.io deu que não existe, então pode ser retirada.

Opa, consegui fazer funcionar. Só joguei a linha do elo para ser a primeira regex para checar e funcionou em todos (após remover o 5031433215406351)

Segue o código completo:

export function getCardBrandName (cardNumber: string): string | null {
  const numbers = cardNumber.replace(/[^0-9]+/g, '')

  const brands = {
    elo: /^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^50(4175|6699|67[0-6][0-9]|677[0-8]|9[0-8][0-9]{2}|99[0-8][0-9]|999[0-9])|^627780|^63(6297|6368|6369)|^65(0(0(3([1-3]|[5-9])|4([0-9])|5[0-1])|4(0[5-9]|[1-3][0-9]|8[5-9]|9[0-9])|5([0-2][0-9]|3[0-8]|4[1-9]|[5-8][0-9]|9[0-8])|7(0[0-9]|1[0-8]|2[0-7])|9(0[1-9]|[1-6][0-9]|7[0-8]))|16(5[2-9]|[6-7][0-9])|50(0[0-9]|1[0-9]|2[1-9]|[3-4][0-9]|5[0-8]))/,
    amex: /^3[47][0-9]{13}$/,
    aura: /^((?!504175))^((?!5067))(^50[0-9])/,
    banese_card: /^636117/,
    cabal: /(60420[1-9]|6042[1-9][0-9]|6043[0-9]{2}|604400)/,
    diners: /(36[0-8][0-9]{3}|369[0-8][0-9]{2}|3699[0-8][0-9]|36999[0-9])/,
    discover: /^6(?:011|5[0-9]{2})[0-9]{12}/,
    fort_brasil: /^628167/,
    grand_card: /^605032/,
    hipercard: /^606282|^3841(?:[0|4|6]{1})0/,
    jbc: /^(?:2131|1800|35\d{3})\d{11}/,
    mastercard: /^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/,
    personal_card: /^636085/,
    sorocred: /^627892|^636414/,
    valecard: /^606444|^606458|^606482/,
    visa: /^4[0-9]{15}$/
  }

  const match = Object.entries(brands).find(([_, value]) => {
    if (value.test(numbers)) {
      return true
    }
    return false
  })

  if (match) {
    return match[0]
  }

  return null
}

const cards = {
  // PagSeguro
  // https://dev.pagbank.uol.com.br/reference/cartoes-de-teste
  '4539620659922097': 'visa',
  '4929291898380766': 'visa',
  '5240082975622454': 'mastercard',
  '5530062640663264': 'mastercard',
  '345817690311361': 'amex',
  '372938001199778': 'amex',
  '4514161122113757': 'elo',
  '4389350446134811': 'elo',
  '6062828598919021': 'hipercard',
  '6062822916014409': 'hipercard',
  // https://dev.pagbank.uol.com.br/reference/criar-pagar-pedido-com-3ds-validacao-pagbank
  '4000000000002701': 'visa',
  '5200000000001005': 'mastercard',
  '6505050000001000': 'elo',
  '4000000000002503': 'visa',
  '5200000000001096': 'mastercard',
  '6505050000001091': 'elo',
  '4000000000002925': 'visa',
  '5200000000001013': 'mastercard',
  '6505050000001018': 'elo',
  '4000000000002370': 'visa',
  '5200000000001104': 'mastercard',
  '6505050000001109': 'elo',
  // Mercado pago
  // https://www.mercadopago.com.br/developers/pt/docs/checkout-api/additional-content/your-integrations/test/cards
  '5067766783888311': 'elo',
  '4235647728025682': 'visa',
  '375365153556885': 'amex',
  // Gerados
  // https://www.vccgenerator.org/
  '5098176533461570': 'elo',
  '5067349319312260': 'elo',
  '5098193894226609': 'elo',
  '5091084515027541': 'elo',
  '5098177024386094': 'elo',
  '4391395999142147': 'visa',
  '4103922157715577': 'visa',
  '4380208328771358': 'visa',
  '4297672575052840': 'visa',
  '4380277454970936': 'visa',
  '5551555128049017': 'mastercard',
  '5268003770982262': 'mastercard',
  '5448382804657501': 'mastercard',
  '5582852950163914': 'mastercard',
  '5448384161742298': 'mastercard',
  '340205640990176': 'amex',
  '340205958483061': 'amex',
  '340205254489929': 'amex',
  '340205493225258': 'amex',
  '340205571301401': 'amex',
};

for (const card in cards) {
    const expectedBrand = cards[card]
    const calculatedBrand = getCardBrandName(card)
    if (expectedBrand == calculatedBrand) {
        console.log(`${card} OK`)
    } else {
        console.log(`${card} ERROR. Expected ${expectedBrand}, got ${calculatedBrand}`)
    }
}

@GabrielLasso

Copy link
Copy Markdown

Eu pequei os cartões dessa resposta do @MMortari :

Boa tarde pessoal,
Minha pequena contribuição, segue uma lista com alguns cartões que estou colecionando de alguns provedores para teste.

const cards = {
  // PagSeguro
  // https://dev.pagbank.uol.com.br/reference/cartoes-de-teste
  '4539620659922097': EnumCardBrand.VISA,
  '4929291898380766': EnumCardBrand.VISA,
  '5240082975622454': EnumCardBrand.MASTERCARD,
  '5530062640663264': EnumCardBrand.MASTERCARD,
  '345817690311361': EnumCardBrand.AMEX,
  '372938001199778': EnumCardBrand.AMEX,
  '4514161122113757': EnumCardBrand.ELO,
  '4389350446134811': EnumCardBrand.ELO,
  '6062828598919021': EnumCardBrand.HIPERCARD,
  '6062822916014409': EnumCardBrand.HIPERCARD,
  // https://dev.pagbank.uol.com.br/reference/criar-pagar-pedido-com-3ds-validacao-pagbank
  '4000000000002701': EnumCardBrand.VISA,
  '5200000000001005': EnumCardBrand.MASTERCARD,
  '6505050000001000': EnumCardBrand.ELO,
  '4000000000002503': EnumCardBrand.VISA,
  '5200000000001096': EnumCardBrand.MASTERCARD,
  '6505050000001091': EnumCardBrand.ELO,
  '4000000000002925': EnumCardBrand.VISA,
  '5200000000001013': EnumCardBrand.MASTERCARD,
  '6505050000001018': EnumCardBrand.ELO,
  '4000000000002370': EnumCardBrand.VISA,
  '5200000000001104': EnumCardBrand.MASTERCARD,
  '6505050000001109': EnumCardBrand.ELO,
  // Mercado pago
  // https://www.mercadopago.com.br/developers/pt/docs/checkout-api/additional-content/your-integrations/test/cards
  '5067766783888311': EnumCardBrand.ELO,
  '5031433215406351': EnumCardBrand.MASTERCARD,
  '4235647728025682': EnumCardBrand.VISA,
  '375365153556885': EnumCardBrand.AMEX,
  // Gerados
  // https://www.vccgenerator.org/
  '5098176533461570': EnumCardBrand.ELO,
  '5067349319312260': EnumCardBrand.ELO,
  '5098193894226609': EnumCardBrand.ELO,
  '5091084515027541': EnumCardBrand.ELO,
  '5098177024386094': EnumCardBrand.ELO,
  '4391395999142147': EnumCardBrand.VISA,
  '4103922157715577': EnumCardBrand.VISA,
  '4380208328771358': EnumCardBrand.VISA,
  '4297672575052840': EnumCardBrand.VISA,
  '4380277454970936': EnumCardBrand.VISA,
  '5551555128049017': EnumCardBrand.MASTERCARD,
  '5268003770982262': EnumCardBrand.MASTERCARD,
  '5448382804657501': EnumCardBrand.MASTERCARD,
  '5582852950163914': EnumCardBrand.MASTERCARD,
  '5448384161742298': EnumCardBrand.MASTERCARD,
  '340205640990176': EnumCardBrand.AMEX,
  '340205958483061': EnumCardBrand.AMEX,
  '340205254489929': EnumCardBrand.AMEX,
  '340205493225258': EnumCardBrand.AMEX,
  '340205571301401': EnumCardBrand.AMEX,
};

E usei os regex da última resposta, conforme o @gfucci colocou em sua resposta:

Comlementando, os cartões que deram errado passam na REGEX da bandeira esperada, mas também passam na da Discover/Aura. Eu comentei essas duas bandeiras e a maioria passou, só o 5031433215406351 que não está passando na REGEX do mastercard

Isso acontece porque o padrão desses cartões ELO realmente batem com o padrão da discover, porém por algum motivo a caixa registrou o BIN antes (não sei como funciona esses registros de BIN). Essas exceções já estão no regex da elo, podemos ver na parte "|6505[0-2][0-9]". Se jogarmos no bincheck.io inicialmente ele também da discover, mas se fizer o POST pra verificar ele irá retornar elo.
pra resolver podemos criar um switch e dar break antes para não continuar a verificação, e sempre verificar o ELO primeiro. Um exemplo em PHP

$bandeira = match (1) {
            preg_match(
                '/^4011(78|79)|^43(1274|8935)|^45(1416|7393|763(1|2))|^504175|^627780|^63(6297|6368|6369)|(65003[5-9]|65004[0-9]|65005[01])|(65040[5-9]|6504[1-3][0-9])|(65048[5-9]|65049[0-9]|6505[0-2][0-9]|65053[0-8])|(65054[1-9]|6505[5-8][0-9]|65059[0-8])|(65070[0-9]|65071[0-8])|(65072[0-7])|(65090[1-9]|6509[1-6][0-9]|65097[0-8])|(65165[2-9]|6516[67][0-9])|(65500[0-9]|65501[0-9])|(65502[1-9]|6550[34][0-9]|65505[0-8])|^(506699|5067[0-6][0-9]|50677[0-8])|^(509[0-8][0-9]{2}|5099[0-8][0-9]|50999[0-9])|^65003[1-3]|^(65003[5-9]|65004\d|65005[0-1])|^(65040[5-9]|6504[1-3]\d)|^(65048[5-9]|65049\d|6505[0-2]\d|65053[0-8])|^(65054[1-9]|6505[5-8]\d|65059[0-8])|^(65070\d|65071[0-8])|^65072[0-7]|^(65090[1-9]|65091\d|650920)|^(65165[2-9]|6516[6-7]\d)|^(65500\d|65501\d)|^(65502[1-9]|6550[3-4]\d|65505[0-8])/', 
                $cartaoNumero
            ) => 'elo',
            preg_match('/^4[0-9]{12}(?:[0-9]{3})?/', $cartaoNumero) => 'visa',
            preg_match('/^((5(([1-2]|[4-5])[0-9]{8}|0((1|6)([0-9]{7}))|3(0(4((0|[2-9])[0-9]{5})|([0-3]|[5-9])[0-9]{6})|[1-9][0-9]{7})))|((508116)\\d{4,10})|((502121)\\d{4,10})|((589916)\\d{4,10})|(2[0-9]{15})|(67[0-9]{14})|(506387)\\d{4,10})/', $cartaoNumero) => 'mastercard',
            preg_match('/^3[47][0-9]{13}/', $cartaoNumero) => 'amexs',
            preg_match('/^65[4-9][0-9]{13}|64[4-9][0-9]{13}|6011[0-9]{12}|(622(?:12[6-9]|1[3-9][0-9]|[2-8][0-9][0-9]|9[01][0-9]|92[0-5])[0-9]{10})/', $cartaoNumero) => 'discover',
            preg_match('/^3(?:0[0-5]|[68][0-9])[0-9]{11}/', $cartaoNumero) => 'diners',
            preg_match('/^(?:2131|1800|35\d{3})\d{11}/', $cartaoNumero) => 'jcb',
            preg_match('/^(606282\d{10}(\d{3})?)|(3841\d{12})|(637\d{13})/', $cartaoNumero) => 'hipercard',
            default => ''
        };

Agora todos os números vão bater corretamente!
Esta bandeira 5031433215406351 no bincheck.io deu que não existe, então pode ser retirada.

Aparentemente está falhando para alguns ainda... Olha o resultado que eu tive:

image

Qual código você tá usando?

No meu exemplo em TypeScript funcionou todos os cartões

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment