2

The following PHP code explodes a multi-line string into an array. And then three if statements are used to check whether a specific line exists in the array and echo the corresponding text if any of them exists.

$multiline_string = 'First line
Second line
Third line';

$array = explode("\n", $multiline_string);

if (in_array('First line', $array))
{
    echo 'First line exists.';
}

if (in_array('Second line', $array))
{
    echo 'Second line exists.';
}

if (in_array('Third line', $array))
{
    echo 'Third line exists.';
}

The issue is that only Third line exists. is being echoed, meaning the first line and the second line were not found in the array.

But I did a debug by using print_r($array) and got this output:

Array
(
    [0] => First line
    [1] => Second line
    [2] => Third line
)

So the first line and the second line do exist in the array. Why didn't the in_array function find them?

12
  • 4
    you probably have dos line endings and "First line" is actually "First line\r" Commented Sep 14, 2019 at 3:49
  • This answer explains is pretty well: stackoverflow.com/a/3274747/2763026 Commented Sep 14, 2019 at 3:51
  • 1
    You could use preg_split on \R instead: 3v4l.org/HUXr6 Commented Sep 14, 2019 at 4:11
  • It is already works fine.:paiza.io/projects/DrHniWO-qNuL-O7rS44DpQ Commented Sep 14, 2019 at 4:17
  • @Sorin Thanks for the tip. I just tried changing explode("\n", $multiline_string) to explode("\r\n", $multiline_string), and it works. So it was the issue of dos line endings. Commented Sep 14, 2019 at 4:23

3 Answers 3

1

Background

To undestand what's going on you need to understand that there are multiple conventions regarding how the end of a line should be represented in a text file.

  • Text files generated on Unix/Apple machines usually separate lines with a single newline character: \n.
  • Text files generated on Windows machines usually separate lines with two characters, carriage-return + line-feed: \r\n.
  • Text files generated on very old Apple machines usually separate lines with a carriage return character: \r. You probably don't need to worry about this as it is very rarely encountered in practice.

Wikipedia has a good summary that explains the history of these different standards.

Your problem

It looks like your example file was created on Windows, and therefore there are two characters between each line. This means that when you explode() on \n each line except for the last one will contain an invisible \r character at the end. This is why only the last line is matching in your example.

Solutions

There are a couple of solutions to this, depending on where your multi-line string data comes from.

If your situation is as indicated in your example, where the string is defined as a literal string in a file you control, you have two options:

  1. Convert the file to use Unix-style line endings. Most text editors/IDEs allow you to do this via a menu option. You only need to do this once per file (assuming you save it having made the change). If you make this change, your current code will work as-is.
  2. Update your code to use $array = explode("\r\n", $multiline_string); so that you are exploding based on Windows line-endings.

If, on the other hand, your data comes from user input then you should code it to handle both types of line-endings1. There are a couple of options here, too:

  1. Make sure the code that performs the split recognises both line ending styles. The simplest way is to replace the explode() call with $array = preg_split("/\r?\n/", $multiline_string), which will explode on any instance of \n or \r\n.
  2. Convert one line-ending style to the other, so that you know the line-ending style in use, and then use explode(), as before. For example, $multiline_string = str_replace("\r\n", "\n", $multiline_string);. This method is preferable if you are going to do other things with the string later, e.g. store it in the database, as it means you only need to handle this once rather than having to handle both possibilities in all situations.

1 Or all three types, if you want to be thorough. This is left as an excercise for the reader...

Sign up to request clarification or add additional context in comments.

2 Comments

Thanks. Good point regarding using str_replace to make all line-endings the same for later string process.
Thanks - I have updated the answer with details that include the correct regex (rather than deferring to the accepted answer), as the accepted answer is not actually correct. It doesn't output anything except for a number of PHP warnings. This answer is therefore now fully self-contained.
0

If you use double quotes instead of single quotes and add a carriage return \r , it will print out the three lines(notice that we do not put \r for the third one)

<?php

$multiline_string = 'First line
Second line
Third line';

$array = explode("\n", $multiline_string);

dd($array);

if (in_array("First line\r", $array)){ //here we added a carriage return
    echo 'First line exists.'.'<br>';
}

if (in_array("Second line\r", $array)){ //here we added a carriage return
    echo 'Second line exists.'.'<br>';
}

if (in_array("Third line", $array)){ //here we did not
    echo 'Third line exists.'.'<br>';
}

function dd($something){
    echo '<pre>';
    var_dump($something);
    echo '</pre>';
}

and the output will be:

array(3) {  
  [0]=>  
  string(11) "First line  
"  
  [1]=>  
  string(12) "Second line  
"  
  [2]=>  
  string(10) "Third line"  
}

First line exists.

Second line exists.

Third line exists.

Comments

0

Try preg_split instead. It allows you to use a regular expression instead of an exact string match.

$multiline_string = 'First line
Second line
Third line';

$array = preg_split("/\r?\n/", $multiline_string);

if (in_array('First line', $array))
{
    echo 'First line exists.';
}

if (in_array('Second line', $array))
{
    echo 'Second line exists.';
}

if (in_array('Third line', $array))
{
    echo 'Third line exists.';
}

4 Comments

And you might want to add optional whitespace before and after the newline chars, depending on how well-formed the input is. It's easy to add an invisible space at the end of a line, and sometimes careless people might even put spaces at the beginning of the line.
Thanks all. It looks like preg_split is more reliable than explode in this case.
The regex in this answer is invalid: Warning: preg_split() [function.preg-split]: No ending delimiter '?' found in index.php on line 5. You are missing the regex delimiters.
LOL, I forgot about that. What a terrible syntax. The worst of both worlds. I don't think any other language requires you to delimit regular expressions with both quotes and forward slashes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.