• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

pedrotuga

Como filtrar strings de modo a permitir apenas texto sem pontuação

23 mensagens neste tópico

Estava eu todo contente aqui a bater código num projecto meu quando me deparei com o seguinte problema:

A framework que estou a utilizar filtra os URLs todos de forma a que se um parametro tiver um caracter para além de A-Za-z0-9 aquilo dispara uma mensagem de erro.

Esse comportamente pode ser alterado redefinindo uma expressão regular lá nas definições, mas eu não sei bem como filtrar só o que quero.

O objectivo é um sistema de tags em que as tags possam ser passadas por url, mas pontuação e afins não podem ser incluidas.

Então o que eu quero no fim de contas é filtrar as tags de forma a que apenas sejam permitidas palavras mas em qualquer língua.

por exemplo

blablaª  <--- inválido

poção <---- válido

維基百科歡迎您 <----- válido

維基百科歡迎您, <---- inválido por causa da vírgula.

blabla% <---- inválido

Alguma sugestão?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Se calhar o mais fácil é arranjar uma lista de todos os caracteres que não são usados para a escrita ( (){}[]'?«»~^-_ ,.:; etc) e depois verificares se existem.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Se calhar o mais fácil é arranjar uma lista de todos os caracteres que não são usados para a escrita ( (){}[]'?«»~^-_ ,.:; etc) e depois verificares se existem.

Ou talvez não...

O melhor é mesmo aprenderes expressões regulares, caso contrário vais andar às cabeçadas/marretadas e não tens garantia de que a coisa esteja mesmo como deve ser.

Aumentar uma expressão para suportar mais caracteres além de A-Za-z0-9 é bastante simples. Google it, vais encontrar tutoriais e web apps que te permitem fazer experiências para consolidares os conhecimentos.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Eu sei usar expressões regulares. Só que isso não responde à minha pergunta. Escrever a regex não é o problema, o problema é mesmo saber o que filtrar.

A solução sugerida pelo fnds funciona, mas... como arranjar uma relação de todos os caracteres de pontuação em todas as línguas?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bom... não tens que te preocupar com os caracteres unicode presentes em outras línguas.

O RFC 1738 descreve o formato dos URLs. A certa altura podes ler:

[...]URLs are written only with the graphic printable characters of the US-ASCII coded character set. The octets 80-FF hexadecimal are not used in US-ASCII, and the octets 00-1F and 7F hexadecimal represent control characters; these must be encoded.
.

Só tens que te preocupar com US-ASCII e só deves aceitar caracteres dentro do grupo "graphic printable characters of the US-ASCII".

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

mmmm.... está à frente do noso nariz mas ainda nenhum de nós pensou nisso. Ou então eu é que me expliquei mal.

Depois de analizar essa frase cuidadosamente cheguei à conclusão que não ajuda muito aqui para o caso.

Por exemplo, o seguinte URL

http://zh.wikipedia.org/wiki/%E9%A6%96%E9%A1%B5

Se voces tiverem um browser que não seja super-antigo, vêm os caracteres japoneses todos bonitinhos. No entanto se forem ver o código fonte desta página já vêm um url com uma representação alternativa desses caracteres.

Ou seja, o url depois de devidamente condificado no formato próprio para urls terá apenas os caracters ascii referidos nessa especificação. Mas interessa aqui o que está antes.

Por outras palavras, codificação do url à parte, alguem conhece uma filtro (uma regex, uma função, whatever) que remova ou invalide texto com pontuação seja em que língua for?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Assim de repente não me ocorre nada a não ser...

- Testas pela existência dos simbolos tradicionais ascii,

- depois testas pela existência dos caracteres gerais de pontuação unicode (U+2000 a U+206F)

- por fim testas pela existência dos caracteres suplementares de pontuação unicode (U+2E00 – U+2E7F)

os links são PDFs

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

A forma mais directa seria negares todos os elementos de pontuação, que nem são tantos quanto isso. É a forma mais simples de expressão regular. Até porque a pontuação é a mesma, seja em que língua for.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

A forma mais directa seria negares todos os elementos de pontuação, que nem são tantos quanto isso. É a forma mais simples de expressão regular. Até porque a pontuação é a mesma, seja em que língua for.

Não é não. Isso é o que podemos ser levados a pensar assim à primeira, mas há mesmo muita pontuação noutras linguas que nós nunca ouvimos falar.

Por isso é que até abri este tópico, um pouco na esperança de alguem já ter alguma solução funcional

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bom... dei-te uma solução Pedro.

Só não vou é escrever o código e uma pesquisa básica pela web não revelou nada de útil para além dos links que te forneci.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bom... dei-te uma solução Pedro.

Só não vou é escrever o código e uma pesquisa básica pela web não revelou nada de útil para além dos links que te forneci.

Não tinha visto a tua última mensagem.

Mas obrigado, já sei então quais os caracteres de pontuação.

Vou experimentar excluir então desde o 2000 até ao 206f

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Se calhar deve-me estar a escapar algo. Mas não basta comparar se é uma letra ou não? Qualquer linguagem em condições nos dias de hoje tem um bom suporte para Unicode, portanto verificar se é uma letra, dígito, pontuação, etc, deveria de ser independente do idioma usado.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Se calhar deve-me estar a escapar algo. Mas não basta comparar se é uma letra ou não? Qualquer linguagem em condições nos dias de hoje tem um bom suporte para Unicode, portanto verificar se é uma letra, dígito, pontuação, etc, deveria de ser independente do idioma usado.

Arranjas uma relação das letras todas nas linguagens todas? É que o unicode até inclui algumas linguagens que já não são usadas há milhares de anos, e acho que o mapeamento UTF8 tem representação para quase todas.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Ora aqui está mais uma solução. Obrigado Rui Carlos.

Segundo esse mesmo site o PHP tambem tem suporte UTF para expressões regulares PCRE que são as que eu uso ;) bastando para isso colocar o modificador u// Hurray!

Assim tenho a vida ainda mais facilitada.

Vou fazer testar durante algum tempo as duas soluções, depois logo se vê qual é que dá mais jeito.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Mmmm... não sei até que ponto é que este identificador está presente nas implementações das PCRE que por aí andam.

Isto não me está  a validar uma string só com letras.

preg_match('/\^p{Letter}+$/u', $tagstring)

Realmente bem me pareceu estranho quando vi este identificador pois não tinha conhecimento da sua existencia e li o perldoc na sua integra.

Afinal de contas isto deve ser uma coisa bem recente pois não é referido em lado nenhum na documentação ofcial do perl.

Mas o mais certo é algum glitch na minha expressão regular.

Alguem nota alguma coisa de errado?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Hmm.... Não tenho o PHP nesta máquina para testar, mas talvez nesse caso queiras isto:

'^/p{L}+$/u'

ou ainda

'^/pL+$/u'

Não conheço {Letter}. O mais próximo que conheço são os metacharacters, mas a syntax destes é [:código:].

Entretanto, existe realmente em PHP /p{código}. No caso o código será L para letras do alfabeto.  /p{} só funciona com o modo UTF-8 activo (/u) e podes simplificar retirando as chavetas porque estás a usar um código de uma só letra.

Sem ter testado isto, penso que o exemplo acima irá devolver 1 se a string contiver apenas letras.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

mmm, essas strings não valdam como expressões regulares pois o quantificador de negação, o acento circunflexo, está fora dos delimitadores. E tambem estás confundido com a definição de classes de caracteres, é \p{...} ou \P{...}, falta aí o caracter de escape, para esse 'p' não compilar como a letra P.

Tirando esses bugs ficas com uma expressão regular igual à minha :s pois esse L é um alias do Letter que o rui carlos referiu.

Esa sintaxe das cavetas rectas é  serve para identificar classes de caracteres posix, não sei se as posso usar numa pcrel, mas tanto quanto sei há um equivalente em perl para cada uma dessas classes, o problema é que não tenho conhecimento de nenhuma classe de caracteres posix que represente todos os codepoints do unicode que correspondam a letras :)

O \p{L} está a perfilar-se como a solução obvia, mas por algum motvo a minha regex não está a validar... não sei se tem algum pequeno bug do qual me estou a esquecer ou se ainda não está implementado na minha biblioteca de PCRE que a minha instalação do PHP usa.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bom... estaria em cima a usar ^ para delimitar o inicio da string e não para negar a classe. Ambos ^ e $ servem também para declarar o início e o fim da string. Termina com $, pelo que só valida se toda a string contiver caracteres.

Porque é que queres negar a pesquisa? Neste caso é indiferente, mas pareceria-me mais correcto não o fazeres uma vez que estás à procura de strings com letras apenas. Seria portanto mais correcto que o resultado fosse compatível com true, em vez de false quando tal acontecesse.

Entretanto tens razão. Meu erro. É \p e não /p. Não devia escrever às 4 da manhã :)

Ainda assim tentaste o código acima corrigindo para \p?

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Bem, as regex são das coisas com mais particularidades minuciosas que existem, a juntar a isso eu ja me enganei inicialmente quando escrevi a minha regex, a seguir enganaste-te tu, o que resultou numa valente confusão :s

Ok, eu escrevi

/\^p{Letter}+$/u

quando queria ter escrito

/^\p{Letter}+$/u

o ^ não é para negar a pesquisa, é para fazer um match no principio. O ^ só serve como negação se estiver dentro da definição manual de uma classe de caracteres.

mas aparentemente o PHP não suporta a sintaxe longa para classes de caracteres na sua implementação das prce, pelo que tenho que usar p{L} em vez de p{Letter}

entretanto com mais umas dicas que já arranjei, vou experimentar isto:

/^[\p{L}\s]++$/uD

Vou tambem incluir espaços, os dois ++ são para acelerar o teste tornando o + greedy.

Como é que voces descobriram o \p{L}??? Não está na documentação :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Como é que voces descobriram o \p{L}??? Não está na documentação :)

Está na minha. Experimenta fazer o download aqui. http://www.php.net/download-docs.php

Não uso a documentação do PCRE como base para as minhas regex no PHP.

Infelizmente durante anos toda a gente achou que era mais esperta que o anterior e pôs-se a criar novas sintaxes ou a criar extensões a sintaxes existentes. Por isso REGEX é a trapalhada que se vê. O PHP não foi diferente. Até uma porcaria de um editor de texto acha que deve mudar a sintax ou adicionar novos elementos à sintax. Não penso que exista um sistema que tenha evoluído de forma mais absurda que o REGEX na ciência computacional. Enfim... boa sorte com esse ;)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Eu cheguei ao \p{L} pesquisando por unicode. É que para ASCII existe o alpha, mas deduzi que não funcionasse com unicode.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Descobri!

http://se.php.net/manual/en/regexp.reference.php

Mas esta página está um pouco escondida, nem sabia da existencia desta página, sempre assumi que o manual do PHP usava como referencia a documentação do perl para as PCRE.

Estava a falar da documentação do perl.

Se lerem o perldoc, em concreto estas páginas:

    * perlre - regular expression regex regexp

    * perlrequick - Perl regular expressions quick start

    * perlretut - Perl regular expressions tutorial

    * perlfaq6 - Regular Expressions

    * perlreref - Perl Regular Expressions Reference

    * perlreguts - Description of the Perl regular expression engine.

    * perlreapi - perl regular expression plugin interface

Essa classe não é referida, por isso é que eu tinha estranhado.

Marfig, as regex até foram evoluindo normalmente sem grandes acidentes, para alem do facto do suporte e documentação para unicode estar a demorar demasiado. O que confunde muitas vezes o pessoal é que o PHP vem com duas bibliotecas de regular expressions, POSIX e PCRE. Mas por exemplo o PHP6 já só vai ter suporte para as últimas.

Sinceramente ainda não percebi porque é que as PCRE são mais usadas, mas a verdade é que actualmente são as únicas que uso.

Bem, mas vou mas é trabalhar que tinha a tarde livre e passai-a a arrochar :)

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora