С учетом некоторого текста
$subject = <<<TEXT
I need a systematic way of replacing each word in a string separately by providing my own input for each word. I want to do this on the command line.
So the program reads in a string, and asks me what I want to replace the first word with, and then the second word, and then the third word, and so on, until all words have been processed.
The sentences in the string have to remain well-formed, so the algorithm should take care not to mess up punctuation and spacing.
Is there a proper way to do this?
TEXT;
Сначала вы разбиваете строку на слова и токены «всего остального» (например, называете их fill ).Для этого полезны регулярные выражения:
$pattern = '/(?P<fill>\W+)?(?P<word>\w+)?/';
$r = preg_match_all($pattern, $subject, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
Теперь задача состоит в том, чтобы преобразовать возвращаемое значение в более полезную структуру данных, такую как массив токенов и индекс всех используемых слов:
$tokens = array(); # token stream
$tokenIndex = 0;
$words = array(); # index of words
foreach($matches as $matched)
{
foreach($matched as $type => $match)
{
if (is_numeric($type)) continue;
list($string, $offset) = $match;
if ($offset < 0) continue;
$token = new stdClass;
$token->type = $type;
$token->offset = $offset;
$token->length = strlen($string);
if ($token->type === 'word')
{
if (!isset($words[$string]))
{
$words[$string] = array('string' => $string, 'tokens' => array());
}
$words[$string]['tokens'][] = &$token;
$token->string = &$words[$string]['string'];
} else {
$token->string = $string;
}
$tokens[$tokenIndex] = &$token;
$tokenIndex++;
unset($token);
}
}
Примерно вы можете затем вывести все слова:
# list all words
foreach($words as $word)
{
printf("Word '%s' used %d time(s)\n", $word['string'], count($word['tokens']));
}
Что даст вам пример текста:
Word 'I' used 3 time(s)
Word 'need' used 1 time(s)
Word 'a' used 4 time(s)
Word 'systematic' used 1 time(s)
Word 'way' used 2 time(s)
Word 'of' used 1 time(s)
Word 'replacing' used 1 time(s)
Word 'each' used 2 time(s)
Word 'word' used 5 time(s)
Word 'in' used 3 time(s)
Word 'string' used 3 time(s)
Word 'separately' used 1 time(s)
Word 'by' used 1 time(s)
Word 'providing' used 1 time(s)
Word 'my' used 1 time(s)
Word 'own' used 1 time(s)
Word 'input' used 1 time(s)
Word 'for' used 1 time(s)
Word 'want' used 2 time(s)
Word 'to' used 5 time(s)
Word 'do' used 2 time(s)
Word 'this' used 2 time(s)
Word 'on' used 2 time(s)
Word 'the' used 7 time(s)
Word 'command' used 1 time(s)
Word 'line' used 1 time(s)
Word 'So' used 1 time(s)
Word 'program' used 1 time(s)
Word 'reads' used 1 time(s)
Word 'and' used 5 time(s)
... (and so on)
Затем вы выполняете работу только с токенами слова,Например, заменив одну строку на другую:
# change one word (and to AND)
$words['and']['string'] = 'AND';
Наконец, вы объединяете токены в одну строку:
# output the whole text
foreach($tokens as $token) echo $token->string;
, что снова дает образец текста:
I need a systematic way of replacing each word in a string separately by providing my own input for each word. I want to
do this on the command line.
So the program reads in a string, AND asks me what I want to replace the first word with, AND then the second word, AND
then the third word, AND so on, until all words have been processed.
The sentences in the string have to remain well-formed, so the algorithm should take care not to mess up punctuation AND
spacing.
Is there a proper way to do this?
Работа выполнена.Убедитесь, что жетоны слова заменены только действительными жетонами слова, поэтому токенизируйте также пользовательский ввод и выдавайте ошибки, если это не единичное слово (не соответствует шаблону слова).
Код /Demo