Home  |  About  | Last |  Submit  |  Contact
AllQuests.com




Previous Question:  [ubuntu] Ntfs file permissions Ubuntu Forums  General HelpNext Question:  [kubuntu] Problems with CHMOD  Absolute Beginner Talk
Question Masking ( SitePoint Forums PHP )
Updated: 2010-07-21 05:55:04 (8)
Masking

Let's assume I have some classes like:

abstract class Mask
{

private $_pattern;

public function __construct($pattern)
{
$this->_pattern = $pattern;
}

final public function maskValue($value)
{
// TODO: what goes here?
return $maskedValue;
}

}

class PhoneMast extends Mask
{

public function __construct()
{
parent::__construct('# (###) ###-####');
}

}

This system should use things like:
# = any number
A = any upper
a = any lower
@ = any upper or lower
and some kind of literal indicator

I tried regex stuff, but all I can seem to do is validate a string that already matches. I want to store data in the db raw, ie. 12223334444.

So what code would go in maskValue() that would make it work with any pattern using the above?

Note: if '1234asdf' were input, only '1 (234)' would be output.

Answers: Masking ( SitePoint Forums PHP )
Masking

You can use regular expression and replace # with their appropriate regex equivalent ("#" with "[0-9]"). Remember to preg_quote() as necessary.

Although I'm not entirely sure as to what your question is.

sk89q

Masking

+1 - bit confused.

Lets deal with the regex question?

Post some examples of exactly the kind of strings you expect will be submitted, and what you want to happen.

It sounds as if you want to be quite forgiving and you want to try and clean them up and continue - rather than detect an error and bomb out.

Complex validation is often better off done in a class of its own, something like a value object that you then pass on, perhaps to a more expensive class, anyway something that goes on and does one simple thing properly.

Cups

Masking

I haven't completely finished it because the regex involved in converting TO the pattern is giving me a headache!

But it works for the telephone number, both ways.

Enjoy.
PHP Code:

<?php

abstract
class Mask{
    
private $_pattern, $backslashcount = 0;
    
public function __construct($pattern){
        
$this->_pattern = $pattern;
    }
    
private function convertToRegex($includeslashes = true){
        return
self::toRegex($this->_pattern, $includeslashes);
    }
    
private static function toRegex($mask, $includeslashes = true){
        
$ret = ($includeslashes) ? '/' : '';
        
$ret .= str_replace(array('(', '[', ']', ')', '*', '?', '#', 'a', 'A', '@'), array('\(', '\[', '\]', '\)', '\*', '\?', '(\d)', '([a-z])', '([A-Z])', '([a-zA-Z])'), $mask);
        
$ret .= ($includeslashes) ? '/' : '';
        return
$ret;
    }
    
final public function plainValue($value){
        
$mask = $this->convertToRegex();
        
$count = 0;
        
$maskcharsonly = preg_replace('/[^#aA@]/', '', $this->_pattern);
        for(
$i = 1; $i <= strlen($maskcharsonly); $i++){
            
$rep .= '\\'.$i;
        }
        
$maskedValue = preg_replace($mask, $rep, $value);
        return
$maskedValue;
    }
    
private function toBackslashed($value){
        
$this->backslashcount++;
        return
"\\\\{$this->backslashcount}";
    }
    
final public function maskValue($value){
        
$mask = preg_replace('/[^#aA@]/', '', $this->_pattern);
        
$pattern = self::toRegex($mask);
        
$mask = preg_replace_callback('/((\(\\\\d\)))/msi', array($this, 'toBackSlashed'), $this->convertToRegex(false));
        
$mask = stripslashes($mask);
        
$maskedValue = preg_replace($pattern, $mask, $value);
        return
$maskedValue;
    }
}
class
PhoneMask extends Mask{
    
public function __construct(){
        
parent::__construct('# (###) ###-####');
    }
}
$p = new PhoneMask();
echo
$p->plainValue('0 (123) 456-7890');
echo
'<br />';
echo
$p->maskValue('01234567890');

Jake Arkinstall

Masking

What about you lose the extra "#-ing" abstraction and just feed the actual base character classes?

public function __construct()
{
parent::__construct('\d (\d\d\d) \d\d\d-\d\d\d\d');
}

(or just the regex) 1 (800) BAD-IDEA

Or just plain rip out anything not alphanum and have done with it?

Cups

Masking

I'll take a look at the above code and see what I can make of it. The truth is, I don't really understand regex patterns so that might be a dead end unless it's explained as if in a "Regex for total and complete idiots" version.

Quote:
Originally Posted by Cups
+1 - bit confused.

Lets deal with the regex question?

Post some examples of exactly the kind of strings you expect will be submitted, and what you want to happen.

It sounds as if you want to be quite forgiving and you want to try and clean them up and continue - rather than detect an error and bomb out.

Complex validation is often better off done in a class of its own, something like a value object that you then pass on, perhaps to a more expensive class, anyway something that goes on and does one simple thing properly.
Validation isn't an issue. But to answer your question:

Form has an input field. Regardless of what they enter, the Model class does type casting on setValue() anyway, so we'll have numbers only. The ModelValidator class check to make sure the number of digits make sense (7, 10, 11 etc...) before we put it in the db. It's only after all this, and the data is being displayed statically, that I want to apply the mask. Think of it like Visual Basics "Format" funtion. That's what I'm trying to do.

If value is 1112222 only 111-2222 is displayed.
If value is 1112223333 only (111) 222-3333 os displayed.
If value is 12223334444 only then 1 (222) 333-4444 is displayed.

The thing is, this should all be handled by the base class, as in the above posts code example. But, it has to handle more than just phones because Final classes derived from it won't all handle phone numbers.

Here's some reference on the function I'm trying to dupe, though maybe not ALL of it. Heh.

http://www.apostate.com/vb-format-syntax

Serenarules

Masking

Quote:
Think of it like Visual Basics "Format" funtion
The less I think about VB, the better!

Maybe you could try something involving sprintf()?

Jake Arkinstall

Masking

sprintf(),

Yeah, that dawned on me too.

That VB Format looks like the monster offspring of date() and number_format()

So to make sure my silly little head has grasped the problem at hand.

Strings are stored in the database, we don't care how they got there.

Because they are there they are valid.

When we get one out, is will be subjected to a process called masking which formats that string in a given way.

That string can be alphanumeric only.

At its most basic I guess that masker has to count the number of chars. If there's too few it does one thing if there is too many it does another thing.

If like, goldilocks says "its just right" then it starts chopping the string up into bits, lets just say it sticks in a space between the bits.

Now, given my tiny brain, that's where I would start - I can feel my unit-testing redbar/greenbar synapses twitching already ... I am already guessing its going to evolve into a TemplateMethod or a Strategy eventually.

But stop.

Its probably gonna be a whole lot faster if you just tell us why Jake's code doesn't do it for you.

Or - see what you can do splitting the string up using the substr() function and sprintf() the "bits" - that way you can stay away from regexes.

Cups

Masking

((I tried linking some info in, but it didn't retain proper formatting. Please review the article linked above for more information on Named Formats, Multiple Sections, and the list of acceptable formatting characters.))

His code works fine, as he intended it. If you read he article I linked, all the specs for what I want are in there. I am currently working on a custom class myself (based in part on Jake's). But there are several variables I am having to work around. But namely the highlights are:

- Must respond to "Named" formats
- Must be able to accept more than one pattern
- Lastly, basic formatting characters


So far, I've worked out how to do the named formats, multiple section logic, and am working on the last bit, the individual patterns based expression. But even here, there are more rules for how it should behave than just what I listed in my original post. For example, in cases where the right-to-left, or left-to-right processing directions changes, or when the mask and source are different lengths, checking for escaped characters and so on. Formats for Curreny, Long, Medium and Short Date and Times and so forth are pulled from application settings.

I realise a lot of this would be much simpler if this were something I was coding simply for myself. However, it's for a long time client and they will be adding self-designed "modules" to the application later. The base classes I design for it need to be able to handle literally anything they throw at it.

I'll post the result when I'm done.

Serenarules

Previous Question:  [ubuntu] Ntfs file permissions Ubuntu Forums  Ubuntu Forums  General HelpNext Question:  [kubuntu] Problems with CHMOD  Ubuntu Forums  Absolute Beginner Talk

- Source: Masking SitePoint Forums PHP
- Previous Question: [ubuntu] Ntfs file permissions Ubuntu Forums Ubuntu Forums General Help
- Next Question: [kubuntu] Problems with CHMOD Ubuntu Forums Absolute Beginner Talk