0

I need to implement the following functionality:

I have a name field which contains both name and surname. This is stored in a database and is in the order 'surname name'.

I am implementing a script which searches through these records. Currently, I managed to check if a string contains a space, if it contains a space it means it is a name and not an ID Card Number for instance. Here is the code:

$query = "John Doe";

$checkIfSpaceExists = strpos($query, " ");

if ($checkIfSpaceExists == "")
{
    //No Space therefore it is not a name
}
else
{
    //Contains space
   $queryExploded = explode(" ", $query);
   foreach ($queryExploded as $q)
   {
      //Here I need the functionality so that if someone entered John Doe
      //2 different strings are saved, which are
      //$string1 = John Doe
      //$string2 = Doe Johns

      //If the name consists of 3 parts, strings for every combination is saved
}

Then I will insert these strings in an SQL statement with the LIKE attribute and there will be a LIKE for both JOHN DOE and DOE JOHN. Hence, if the user can either enter John Doe or Doe John in order to find the result.

Any suggestions on how to do this?

Many thanks

chris

seedg
  • 21,692
  • 10
  • 42
  • 59

5 Answers5

2

Ok, from the start - be sure to read the manual carefully. strpos doesn't do exactly what you think it's doing. Here's how you should check for a space:

if (strpos($query, ' ') === false)  // the triple-equals is important!

After that, it's simply a matter of permutations and combinations. Here's another answer on Stack Overflow which shows you how to do it: algorithm that will take number or words and find all possible combinations

Community
  • 1
  • 1
nickf
  • 537,072
  • 198
  • 649
  • 721
  • If I use it like you are stating, the script doesn't work well. If instead I use the original one, it works well. I will be updating my post because I implemented it successfully. – seedg Dec 03 '09 at 12:40
  • Can you tell me what is wrong with the way I am using it? thanks – seedg Dec 03 '09 at 12:49
  • The manual has a section highlighted in red with a very large warning sign, which reads: `This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE, such as 0 or "". Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.` – nickf Dec 03 '09 at 13:18
1

What about using these exploded 3 strings in separate AND-combined LIKE-constraints?

Something like

"... WHERE name LIKE '%$name[0]%' AND name LIKE '%$name[1]%' AND name LIKE '%$name[2]%'"

You could build this String in a foreach loop.

Zeemee
  • 10,486
  • 14
  • 51
  • 81
  • depends if you want to find "Johnathon Doe" and "John Henry Doe". It also won't make use of indices with a wildcard at the start of the string. – nickf Dec 03 '09 at 10:46
0
echo preg_replace('/^(\w+) (\w+)$/', '$2 $1', "John Doe");

Doe John

oliver31
  • 2,523
  • 3
  • 19
  • 25
  • this doesn't handle multiple spaces (3 or more words) – nickf Dec 03 '09 at 10:46
  • preg_replace('/^(\w+) (\w+) (\w+)$/', '$3 $2 $1', "John Jay Doe"); preg_replace('/^(\w+) (\w+) (\w+)$/', '$3 $1 $2', "Jay John Doe"); Happy? 3 Parts, thats all he asked for... – oliver31 Dec 03 '09 at 11:04
0

I guess you cannot split this field into name and surname? I suggest creating new table, tags in database. Tags will be any word - might be surname, may be name, may be ID number... Then make a connection record_tags with record_id and tag_id. Then the query will look like

SELECT record.* FROM record
INNER JOIN record_tags rt1 ON rt1.record_id = record.id
INNER JOIN tag t1 ON t1.id = rt1.tag_id
INNER JOIN record_tags rt2 ON rt2.record_id = record.id
INNER JOIN tag t2 ON t2.id = rt2.tag_id
WHERE
t1.name = "John"
AND t2.name = "Doe"

This will be better approach to searching, as you can then use any amount of words/tags. I think the SQL can be even easier. the multiple-like approach is I think much slower, especially as your database grows.

Tomasz Struczyński
  • 3,273
  • 23
  • 28
  • No I cannot split the field. The database is updated every couple of months. It is an un-normalized table containing various personal information, such as name etc... When the database is updated, a new table is created with all the information. The previous tables are only there for backup purposes. The front-end program (implemented with ExtJs) only searches from the last table created. It ignores all the others. There are thousands of records and it is incredibly fast... – seedg Dec 03 '09 at 12:52
0

With some looping and string manipulation, I managed to implement this script.

Here is what I did:

I checked if the query contains a space using strpos. If it contains a space, then it means its a name with both name and surname so I enter a loop in order to output one string with 'name surname' and the other string with 'surname name'

Here is the code:

   $like = ""; //This is the LIKE sql command.
   foreach ($selectedFields as $field)
   {
            $checkIfSpaceExists = strpos($query," ");

    if ($checkIfSpaceExists != "")
    {
        $query1 = $query; //No space, so query1 is equal ta original query

        $queryExploded = explode(" ", $query);

        for ($i=0; $i<count($queryExploded); $i++) //First loop (name surname)
        {
            $tmp1 = $tmp1 . " " . $queryExploded[$i];
        }

        for ($i=count($queryExploded); $i>=0; $i--) //Second loop (surname name)
        {
            $tmp2 = $tmp2 . " " . $queryExploded[$i];

        }
        $query2 = $tmp2;
        $query2 = trim($query2);

        $like = $like . $field . " LIKE '%" . $query1 . "%' or " . $field . " LIKE '%" . $query2 . "%' or ";

I hope this helps someone else in need :)

seedg
  • 21,692
  • 10
  • 42
  • 59